【问题标题】:How do you implement the destructor in CRTP?如何在 CRTP 中实现析构函数?
【发布时间】:2017-08-18 15:45:03
【问题描述】:

在实现奇怪的循环模板模式 (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)

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

【问题讨论】:

    标签: c++ crtp


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      在您展示的示例中,不需要虚拟析构函数。仅当您可能需要使用指向基类的指针调用它时才需要虚拟析构函数,就像在这种情况下覆盖函数必须是虚拟的一样。在您展示的 CRTP 类的情况下,很少需要删除 Base&lt;T&gt; 而不是 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;
      }
      

      【讨论】:

        【解决方案3】:

        如果您要在指向派生对象的基类指针上调用delete,那么您需要一个虚拟析构函数,仅此而已。 CRTP 或没有 CRTP。

        【讨论】:

          猜你喜欢
          • 2021-12-11
          • 1970-01-01
          • 2023-03-29
          • 1970-01-01
          • 2011-04-06
          • 1970-01-01
          • 1970-01-01
          • 2019-07-31
          • 1970-01-01
          相关资源
          最近更新 更多