0

在一个项目中,我有以下问题:

我有一个非常简单的继承方案(我需要继承而不是组合):

类基础

-> 类 DerivedA

-> 类 DerivedB

-> 类 DerivedC

A、B 和 C 从 Base 派生,仅此而已。所以现在我有两个选择:

具有虚拟性的公共继承

没有虚拟性的私有继承

由于某些优化原因(我需要大量内联),我不想要虚拟性......而且我不想要私有继承。我认为剩下的唯一选择是 CRTP。但是基类有大约 300 个函数,在其中实现 CRTP 将是一个真正的痛苦。

所以我想知道以下解决方案是否有效:我只在基类的析构函数中使用 CRTP:

template<class TCRTP> class Base
{
    ~Base() {delete static_cast<TCRTP*>(this);}
}

其中 TCRTP 将是 DerivedA、B 或 C,我进行公共继承。完全没问题,还是有问题?

非常感谢你。

4

2 回答 2

8

你的析构函数肯定是错误的。类的析构函数不会也不应该delete是对象的内存。

你反对没有虚函数的公共继承?有(至少)几种方法可以防止有人通过基指针意外删除派生对象。一是制作基础析构函数protected

另一种是将派生类的动态分配实例直接填充到shared_ptr. 这甚至可以是shared_ptr<Base>

std::shared_ptr<Base> foo(new DerivedA(...));

因为shared_ptr有一个模板构造函数来捕获其参数的类型,所以Base*指针将DerivedA*在与 关联的删除器函数中转换为shared_ptr,因此被正确删除。没有人应该愚蠢到试图从 a 中提取指针shared_ptr并将其删除为Base*.

当然,如果您没有虚函数,那么只有当派生类之间的唯一区别在于它们在构造函数中设置的内容时,这个技巧才真正有用。否则,您最终需要从 向下转换Base*指针shared_ptr,在这种情况下,您应该使用 ashared_ptr<DerivedA>开头。

于 2012-05-25T13:36:58.847 回答
1

我可以看到在 的实现中使用类似代码IUnknown::Release,但从来没有在析构函数中使用。析构函数仅在派生对象被销毁后运行,在该点Base尝试delete派生对象是未定义的行为。我很确定在这种特殊情况下你会得到无限递归。

于 2012-05-25T13:49:18.930 回答