如何在CRTP中实现析构函数?

时间:2017-08-18 15:45:04

标签: c++ crtp

在实施奇怪的重复模板模式(CRTP)时,析构函数是否需要是虚拟的?如果没有,那么适当的非虚拟实现是什么?

我将提供一个有希望让事情变得更容易的例子:

template<typename T>
class Base
{
public:
    virtual ~Base()
    {
        // Should this be virtual? Non-virtual?
        std::cout << "Base::~Base()\n";
    }
};

class Derived : public Base<Derived>
{
public:
    ~Derived() override
    {
        std::cout << "Derived::~Derived()\n";
    }
};

int main()
{
    Base<Derived>* b = new Derived;
    delete b;
}

结果:

Derived::~Derived()
Base::~Base()

Live Sample Here

编辑:更新了示例以使用运行时多态性,以便正确清理虚拟析构函数。

3 个答案:

答案 0 :(得分:3)

在这个意义上,CRTP基类与任何其他基类没有什么不同。只有当您通过指向delete的指针Derived Base<Derived>类型的对象时,才需要虚拟析构函数。否则,不需要虚拟析构函数。

Base<Derived>* b = new Derived;
delete b; // Base<Derived>::~Base<Derived> must be virtual

答案 1 :(得分:1)

在您展示的示例中,不需要虚拟析构函数。当您需要使用指向基类的指针调用它时,只需要一个虚拟析构函数,就像在这种情况下重写函数必须是虚函数一样。对于您所展示的CRTP类,很少需要删除Base<T>而不是T本身。

int main()
{
    Derived *a = new Derived();
    // we have the right type anyway, so dont actually need a virtual anything (even normal virtual methods)
    delete a;

    Derived *a = new Dervied();
    Base<Derived> *b = a;
    // We are now deleting via a parent class, so this needs a virtual destructor.
    // This is pretty uncommon with a simple CRTP however.
    delete b;
}

答案 2 :(得分:0)

如果你打算在一个指向派生对象的基类的指针上调用delete,那么你需要一个虚拟析构函数,这就是它的全部内容。 CRTP或没有CRTP。