我创建了一个容器来控制某些类型对象的生命周期(new / delete),以避免任何编程错误。例如,删除对象而不向容器发送任何通知。对象继承自相同的基类(GreetingBase)。
对于实现,我使用的是“模板技巧”:
class GreetingBase{
public:
virtual void sayHello(){
std::cout << "Hello there!" << endl;
}
virtual ~GreetingBase(){}
};
class GreetingDerived: public GreetingBase{
public:
virtual void sayHello(){
std::cout << "Hola amigos!" << endl;
}
virtual ~GreetingDerived(){}
};
class GreetingContainer{
public:
template <class T>
void addClass(){
items.push_back(new T());
}
~GreetingContainer(){
for(std::vector<GreetingBase*>::iterator it = items.begin();
it < items.end(); it++ ){
delete *it;
}
}
void talk(){
for(std::vector<GreetingBase*>::iterator it = items.begin();
it < items.end(); it++ ){
(*it)->sayHello();
}
}
private:
std::vector<GreetingBase*> items;
};
int main(){
GreetingContainer container;
container.addClass<GreetingDerived>();
container.talk();
return 0;
}
问题:
提前谢谢。
答案 0 :(得分:2)
使用模板来解决这个问题是一种常见的方法吗?
我不知道它是否常见,但看起来很合理。它确保您的容器只能包含指向new
分配的对象的指针,这很好。
有什么缺点吗?
主要问题是您的容器会破坏Rule of Three。它有一个隐式生成的复制构造函数和复制赋值运算符,它只是复制每个指针;这将为您提供两个容器对象,其析构函数都试图删除相同的对象。
解决这个问题的最简单方法是删除这些成员函数,或者如果您遇到2011版之前的语言,则将其声明为私有(没有实现)。如果您需要能够复制容器,那么您需要实现它们才能安全地进行复制。
就个人而言,我会使用智能指针而不是滚动我自己的RAII容器; std::unique_ptr
如果容器具有独占所有权,std::shared_ptr
如果要共享所有权,或std::weak_ptr
保持对通过共享指针在其他地方管理的对象的非拥有引用。如果您遇到过去,那么unique_ptr
将无法使用,但是Boost会提供shared_ptr
,weak_ptr
以及Pointer containers与您类似的内容。
当“T”不是从“GreetingBase”派生时报告更好的错误消息的任何“标准方式”
在C ++ 11中,您可以使用静态断言,例如:
static_assert(std::is_base_of<GreetingBase, T>::value,
"Wrong type for GreetingContainer");
或者,您可以通过创建本地指针来获得稍微更易读的错误消息;那么错误消息至少不会包含push_back
的全名:
GreetingBase * p = new T();
items.push_back(p);
错误消息类似can't convert Whatever* to GreetingBase*
,应该足够清楚。
答案 1 :(得分:1)
template
,但使用函数,收到pointer to base-class
会更好。static_assert
与std::is_base_of一起使用。没有C ++ 11 - 提升等价物,或你自己的元功能。附注:如果您使用smart pointers
,则无需编写此类容器
答案 2 :(得分:0)
我认为使addClass
成为模板没有任何好处;它只是意味着您获得了为每种不同类型实例化的代码的新副本,并且您正在执行特定的构造函数调用。
只需将它作为基类指针的普通函数:
void addClass(GreetingBase *o){
items.push_back(o);
}
所以你的来电者
container.addClass( new GreetingDerived() );
而不是
container.addClass<GreetingDerived>();