【发布时间】:2014-06-09 11:57:21
【问题描述】:
假设我有类Square 和Circle,它们都派生自Shape,还有一个Shape * p2shape 指针,它应该得到一个类型由string shapeName 决定的新对象。
目前,我正在使用以下方法:
enum class Shapes {square, circle};
std::map<string, Shapes> sMap;
sMap["square"] = Shapes::square;
sMap["circle"] = Shapes::circle;
switch (sMap[shapeName]) {
case Shapes::square:
p2shape = new Square();
break;
case Shapes::circle:
p2shape = new Circle();
break;
}
这样做的缺点是添加一个新的派生类需要在三个额外的地方进行更改:
- 向类添加新项目
- 将类添加到地图中
- 将该类添加到
switch
我决定找到一个更简单的解决方案,最终得到了两个版本,这两个版本都通过使用指向创建新对象的静态函数的指针来避免switch命令:
class Square : public Shape {
public:
static Shape * create() { return new Square(); }
};
class Circle : public Shape {
public:
static Shape * create() { return new Circle(); }
};
std::map<string, Shape * (*) ()> sMap;
sMap["square"] = Square::create;
sMap["circle"] = Circle::create;
p2shape = sMap[shapeName]();
这意味着一个新的派生类只需要在一个额外的地方进行更改,即地图。此外,每个派生类都必须具有静态create() 方法。经过一些额外的搜索,我发现我可以使用CRTP 摆脱后一个要求,但代价是额外的复杂性:
template <class DerShapeT>
class Shape_CRTP : public Shape {
public:
static Shape * create() { return new DerShapeT(); }
};
class Square : public Shape_CRTP<Square> {};
class Circle : public Shape_CRTP<Circle> {};
std::map<string, Shape * (*) ()> sMap;
sMap["square"] = Square::create;
sMap["circle"] = Circle::create;
p2shape = sMap[shapeName]();
由于我从未使用过(甚至听说过)CRTP,我想问一下这种方法是否有一些缺点? (好处是不需要所有派生类中的create() 方法。)
而且,更重要的是,有没有更好的方法是我没有想到的?
谢谢。
【问题讨论】:
标签: c++ inheritance crtp