[ACCEPTED]-C++: Inherit class from template parameter-design-patterns
It's often used to realize static polymorphism.
Use cases are:
In 5 general you have the benefits from dynamic 4 polymorphism, without the extra runtime 3 costs of virtual functions. But it's only 2 useful if the concrete type can be determined 1 at compile time.
Sounds like a good candidate for a wrapper 3 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 2 provide synchronized access to the derived 1 classes.
It is used frequently in the so called "policy-based" design, i.e. you 13 add characteristics to a base class by composition 12 with desired derived classes, see "Modern 11 C++ Design: Generic Programming and Design 10 Patterns Applied" by Andrei Alexandrescu. The 9 instantiated template class from which you 8 derive is called the "policy". Such 7 a design is sometimes better than inheritance, as 6 it allows to combine policies and avoid 5 a combinatorial explosion inevitable in 4 the inheritance-based model.
See for example 3 the following simple code, where RED
and BLUE
are 2 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 1 here: http://en.wikipedia.org/wiki/Policy-based_design
A place where I use this style was where 14 I need to implement a generic graph library 13 which is both easy to use and also easy 12 to maintain After a while I came with this 11 design :
ABstract class for GraphContainer,Edge,Node 10 :
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 9 by inheriting directly from template parametrs .
for example My Adj List classess looks 8 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 7 class inherit directly from template too 6 :
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 5 you can simply change the whole class underlying's 4 stuffs by just inherit from abstract classes 3 and fill the template parametrs.
for example 2 I define Trie data structure by simply 1 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_;
}
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.