在项目中,我遇到以下问题:
我有一个非常简单的继承方案(我需要继承而不是组合):
class Base
- > class DerivedA
- > DerivedB类
- > class DerivedC
A,B和C派生自Base,这就是全部。 所以现在我有两个选择:
虚拟公共继承
没有虚拟的私有继承
出于某些优化原因(我需要很多内联)我不想要虚拟......我不想要私有继承。我认为唯一的选择是CRTP。但是基类有300个功能,在其中实现CRTP将是一个真正的痛苦。
所以我想知道以下解决方案是否有效:我只在基类的析构函数中使用CRTP:
template<class TCRTP> class Base
{
~Base() {delete static_cast<TCRTP*>(this);}
}
其中TCRTP将是DerivedA,B或C,我做公共继承。 它完全没问题,还是有问题?
非常感谢。
答案 0 :(得分:8)
你的析构函数肯定是错误的。类的析构函数不会且不能delete
对象的内存。
对没有虚函数的公共继承有什么异议? (至少)有两种方法可以防止某人通过基指针意外删除派生对象。一种是制作基础析构函数protected
。
另一种方法是将派生类的动态分配实例直接填充到shared_ptr
。这甚至可以是shared_ptr<Base>
:
std::shared_ptr<Base> foo(new DerivedA(...));
由于shared_ptr
具有捕获其参数类型的模板构造函数,因此Base*
指针将在与DerivedA*
关联的删除函数中转换为shared_ptr
,因此删除正确。没有人会如此愚蠢地尝试从shared_ptr
中提取指针并将其删除为Base*
。
当然,如果你没有虚函数,那么当衍生类之间的唯一区别就是它们在构造函数中设置的时候,这个技巧才真正有用。否则,您最终需要从Base*
向下转换shared_ptr
指针,在这种情况下,您应该首先使用shared_ptr<DerivedA>
。
答案 1 :(得分:1)
我可以看到在IUnknown::Release
的实现中使用代码,但从不在析构函数中使用。 Base
析构函数仅在派生对象被销毁后运行,尝试delete
此时派生对象是未定义的行为。我很确定你会在那种特殊情况下获得无限递归。