I have such hierarchy of classes:
template <class Type>
class CrtpBase
{
protected:
Type& real_this()
{
return static_cast<Type&>(*this);
}
};
template <class ChildType>
class Base : CrtpBase<ChildType>
{
public:
void foo()
{
this->real_this().boo();
}
};
class Derived1 : public Base<Derived1>
{
public:
void boo { ... }
};
class Derived2 : public Base<Derived2>
{
public:
void boo { ... }
};
The thing is, I want to use my classes in this way:
std::vector<Base*> base_vec;
base_vec.push_bach(new Derived1());
base_vec.push_bach(new Derived2());
.........
base_vec[0]->foo();
But this isn't possible, because base class for all derived classes is different (actually Base isn't a type at all, it's template). So, is there a way to use crtp with multiple derived classes, alongside with polymorphism?
Indeed there is, you need to add the appropriate non-template base class too:
class AbstractBase
{
public:
virtual ~AbstractBase() {}
virtual void foo() = 0;
};
template <class ChildType>
class Base : CrtpBase<ChildType>, public AbstactBase
{
void foo() override { this->real_this().boo(); }
};
Then, declare your vector as std::vector<AbstractBase*>
.
This does indeed introduce the overhead of dynamic dispatch (which you were probably trying to avoid by using CRTP), but dynamic dispatch is the only way to get runtime polymorphism in C++.
It can still be beneficial, though. For example, if the implementation of foo
is shared by all the derived classes, but calls into many different boo
-style functions (with each derived class having a different implementation of those), you will only pay the dynamic dispatch cost once when invoking foo
, and then all the calls made within foo
are dispatched statically, CRTP-style.
On the other hand, if it's just one call to a boo
-like function within foo
, you may as well make boo
virtual, put non-virtual foo
into the base, thus getting rid of CRTP. The cost will be the same then: a non-virtual dispatch (foo
) and a virtual one (boo
).
Side note, you should strongly consider storing smart pointers in the std::vector
; owning raw pointers are bad practice.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments