我创建了一个容器来控制特定类型对象的生命周期(新/删除),以避免任何编程错误。例如,在不通知容器的情况下删除对象。对象继承自同一个基类(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;
}问题:
提前谢谢你。
发布于 2012-09-25 10:28:10
使用模板来解决这个问题是一种常见的方法吗?
我不知道这是否常见,但看起来很明智。它确保容器只能包含指向用new分配的对象的指针,这是很好的。
有什么缺点吗?
主要问题是您的容器破坏了三条规则。它有一个隐式生成的复制构造函数和复制赋值操作符,它简单地复制每个指针;这将给出两个容器对象,它们的析构函数都试图删除相同的对象。
解决这个问题的最简单的方法是删除这些成员函数,或者声明它们是私有的(没有实现),如果您被困在2011年之前的语言版本中。如果您需要能够复制容器,那么您需要实现它们才能安全地完成。
就我个人而言,我会使用智能指针,而不是滚动自己的RAII容器;如果容器具有独占所有权,则使用std::unique_ptr;如果希望共享所有权,则使用std::shared_ptr,或者使用std::weak_ptr来保存对由共享指针管理的其他地方管理的对象的非所有者引用。如果您停留在过去,那么unique_ptr将不可用,但是Boost提供了与您类似的shared_ptr、weak_ptr和指针容器。
当"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*,应该足够清楚。
发布于 2012-09-25 10:20:37
template是可以的,但是使用函数接收pointer to base-class更好。static_assert与的。没有C++11 - boost等价物,或者你自己的元函数。附带注意:如果使用smart pointers,则不需要编写此类容器。
发布于 2012-09-25 10:24:45
我认为让addClass成为一个模板没有什么好处;它只是意味着您得到了针对每种不同类型实例化的代码的新副本,并且强制执行了特定的构造函数调用。
只需使它成为一个简单的函数,接受一个基类指针:
void addClass(GreetingBase *o){
items.push_back(o);
}所以你的来电者
container.addClass( new GreetingDerived() );而不是
container.addClass<GreetingDerived>();https://stackoverflow.com/questions/12580857
复制相似问题