Reputation: 26405
Are destructors required to be virtual when implementing curiously recurring template pattern (CRTP)? And if not, what is the proper non-virtual implementation?
I'll provide an example to hopefully make things easier:
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;
}
Result:
Derived::~Derived()
Base::~Base()
EDIT: Updated the example to use runtime polymorphism so that the virtual destructor is required for proper cleanup.
Upvotes: 5
Views: 2469
Reputation: 30145
In the example you showed, a virtual destructor is not needed. A virtual destructor is just needed when you may need to call it using a pointer to the base class, the same as an overriden function must be virtual in this case. And in the case of a CRTP class like you showed, there is rarely a need to delete a Base<T>
instead of T
itself.
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;
}
Upvotes: 3
Reputation: 36503
If you're going to call delete
on a pointer of a base class that's pointing to a derived object then you need a virtual destructor, that's all there is to it. CRTP or no CRTP.
Upvotes: 0
Reputation: 10433
A CRTP base class is no different from any other base class in this sense. You will need a virtual destructor only if you are going to delete
an object of type Derived
via a pointer to Base<Derived>
. Otherwise, a virtual destructor is not required.
Base<Derived>* b = new Derived;
delete b; // Base<Derived>::~Base<Derived> must be virtual
Upvotes: 6