I recently saw the following C++ code-snippet
template
class A : public B
{
...
};
and I am wondering in which setting such
It's often used to realize static polymorphism.
Use cases are:
In general you have the benefits from dynamic polymorphism, without the extra runtime costs of virtual functions. But it's only useful if the concrete type can be determined at compile time.
Sounds like a good candidate for a wrapper class:
class base {
public:
virtual void f() = 0;
};
class d1 : public base {
public:
virtual void f() override { ... };
};
class d2 : public base {
public:
virtual void f() override { ... };
};
template <typename T>
class wrapper : public T {
public:
virtual void f() override {
pre_op();
T::f();
post_op();
}
private:
void pre_op() { ... }
void post_op() { ... }
}
int main(int, char**) {
wrapper<d1> w1;
}
For example, the wrapper class can provide synchronized access to the derived classes.
A place where I use this style was where I need to implement a generic graph library which is both easy to use and also easy to maintain After a while I came with this design :
ABstract class for GraphContainer,Edge,Node :
template < class T1,class T2>
class GraphAbstractContainer
{
public:
using Node = T1;
using Edge = T2;
virtual std::list<Node> getConnectedNodes(const Node& node)const = 0;
virtual Node addNode(const Node&) = 0;
//...
};
class GraphAbstracthNode
{
public:
virtual uint32_t getId() const = 0;
virtual void setID(uint32_t id)=0;
//..
};
template<class T>
class GraphAbstractEdge
{
public:
using Node = T;
//GraphAbstractEdge(){}
virtual Node firstNode() const = 0;
virtual Node secondNode() const = 0;
virtual void setFirstNode(const Node& node) = 0;
virtual void setSecondNode(const Node& node) = 0;
//...
};
Then I add Adj_List and Adj Matrix implementation by inheriting directly from template parametrs .
for example My Adj List classess looks some thing like this :
template<class T1 = GraphAbstractContainer<GraphAdjNode,
GraphAdjEdge>>
class GraphAdjListContainer : public T1
{
public:
using Node = typename T1::Node;
using Edge = typename T1::Edge;
//return connected Nodes
virtual std::list<Node> getConnectedNodes(const Node& node) const
{
//..
}
//..
};
};
template<class T>
class GraphAdjNode : public T
{
public:
//implementing abstract class methods...
};
template<class T>
class GraphAdjEdge : public T
{
public:
//...
};
And also My Graph class inherit directly from template too :
template<class GraphContainer=GraphAdjListContainer<>>
class Graph :public GraphContainer
{
public:
using Node = typename GraphContainer::Node;
using Edge = typename GraphContainer::Edge;
//...
}
An advantage for this design pattern is you can simply change the whole class underlying's stuffs by just inherit from abstract classes and fill the template parametrs.
for example I define Trie data structure by simply doing this :
class TrieNode :public GraphAdjNode
{
public:
//...
std::string word_;
};
class Trie
{
public:
using Graph = Graph < ecv::GraphAdjListContainer<TrieNode, ecv::GraphAdjListEdge<TrieNode>>>;
using Node = Graph::Node;
using Edge = Graph::Edge;
void addWord(wstring word);
//...
private:
Graph graph_;
}
It is used frequently in the so called "policy-based" design, i.e. you add characteristics to a base class by composition with desired derived classes, see "Modern C++ Design: Generic Programming and Design Patterns Applied" by Andrei Alexandrescu. The instantiated template class from which you derive is called the "policy". Such a design is sometimes better than inheritance, as it allows to combine policies and avoid a combinatorial explosion inevitable in the inheritance-based model.
See for example the following simple code, where RED
and BLUE
are drawing policies for a Pen
:
#include <iostream>
#include <string>
struct RED
{
std::string getColor()
{
return "RED";
}
};
struct BLUE
{
std::string getColor()
{
return "BLUE";
}
};
template <typename PolicyClass>
class Pencil: public PolicyClass
{
public:
void Draw()
{
std::cout << "I draw with the color " << PolicyClass::getColor() << std::endl;
}
};
int main()
{
Pencil<RED> red_pencil; // Drawing with RED
red_pencil.Draw();
Pencil<BLUE> blue_pencil; // Different behaviour now
blue_pencil.Draw();
return 0;
}
Can read a bit more here: http://en.wikipedia.org/wiki/Policy-based_design