I have a c++ question about CRTP pattern and polymorphism. I want to know if I can put a virtual destructor in a CRTP pattern without causing some undefined behavior when implementing a derived class with CRTP.
I have this code for an abstract class:
struct TensorExpression {
virtual ~TensorExpression() = default;
// ...
};
Then I have derived classes like BinaryOperator
:
template<class Operation>
class BinaryOperator : public TensorExpression {
public:
~virtual BinaryOperator() override = default;
void operation() {
return static_cast<Operation*>(this)->operation_implementation();
}
// some other methods to be implemented with CRTP pattern called with static_cast.
};
Then I want to implement those classes with CRTP to avoid more virtual methods.
class BinaryAdd : public BinaryOperator<BinaryAdd> {
public:
~BinaryAdd() override = default;
//
private:
friend class public BinaryOperator<BinaryAdd>;
void operation_implementation() {
std::cout << "add implementation" ;
}
//
};
My question is, won't a virtual destructor in a CRTP base class cause undefined behavior? and is it necesary? or is there another whay to delete derived CRTP class using a TensorExpression
pointer without using a virtual destructor in BinaryOperator
? I mean, I want to use TensorExpression
polimorphically, but not BinaryOperator
; given that I won't be creating BinaryOperator
pointers directly to be deleted. BinaryAdd
just implements BinaryOperator
.
If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly-declared) is virtual.
You don't need to specify the destructor of BinaryOperator
. It will be declared virtual
because TensorExpression
's destructor is. Same for BinaryAdd
.
There is no reason CRTP would prevent dynamic polymorphism from working correctly. Deleting a BinaryAdd
object through a TensorExpression
pointer will work just fine, simply because the destructor of TensorExpression
is virtual.
Your example structure is even listed as a pattern in the wikipedia page for CRTP.