CRTP中的析构函数是怎么实现的?
How do you implement the destructor in 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()
编辑:更新示例以使用运行时多态性,以便正确清理需要虚拟析构函数。
CRTP 基础 class 在这个意义上与任何其他基础 class 没有什么不同。仅当您要通过指向 Base<Derived>
的指针 delete
类型 Derived
的对象时,才需要虚拟析构函数。否则,不需要虚拟析构函数。
Base<Derived>* b = new Derived;
delete b; // Base<Derived>::~Base<Derived> must be virtual
如果您要在指向派生对象的基 class 的指针上调用 delete
,那么您需要一个虚拟析构函数,仅此而已。 CRTP 或无 CRTP。
在您展示的示例中,不需要虚拟析构函数。当您可能需要使用指向基 class 的指针调用它时,只需要一个虚拟析构函数,就像在这种情况下被覆盖的函数必须是虚拟的一样。在 CRTP class 的情况下,就像你展示的那样,很少需要删除 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;
}
在实现奇怪的循环模板模式 (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()
编辑:更新示例以使用运行时多态性,以便正确清理需要虚拟析构函数。
CRTP 基础 class 在这个意义上与任何其他基础 class 没有什么不同。仅当您要通过指向 Base<Derived>
的指针 delete
类型 Derived
的对象时,才需要虚拟析构函数。否则,不需要虚拟析构函数。
Base<Derived>* b = new Derived;
delete b; // Base<Derived>::~Base<Derived> must be virtual
如果您要在指向派生对象的基 class 的指针上调用 delete
,那么您需要一个虚拟析构函数,仅此而已。 CRTP 或无 CRTP。
在您展示的示例中,不需要虚拟析构函数。当您可能需要使用指向基 class 的指针调用它时,只需要一个虚拟析构函数,就像在这种情况下被覆盖的函数必须是虚拟的一样。在 CRTP class 的情况下,就像你展示的那样,很少需要删除 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;
}