I cannot think about a proper question title to describe the problem. Hopefully the details below explains my problem clear.
Consider the following code
#include <iostream>
template <typename Derived>
class Base
{
public :
void call ()
{
static_cast<Derived *>(this)->call_impl();
}
};
class D1 : public Base<D1>
{
public :
void call_impl ()
{
data_ = 100;
std::cout << data_ << std::endl;
}
private :
int data_;
};
class D2 : public Base<D1> // This is wrong by intension
{
public :
void call_impl ()
{
std::cout << data_ << std::endl;
}
private :
int data_;
};
int main ()
{
D2 d2;
d2.call_impl();
d2.call();
d2.call_impl();
}
It will compile and run though the definition of D2
is intentionally wrong. The first call d2.call_impl()
will output some random bits which is expected as D2::data_
was not initialized. The second and third calls will all output 100
for the data_
.
I understand why it will compile and run, correct me if I am wrong.
When we make the call d2.call()
, the call is resolved to Base<D1>::call
, and that will cast this
to D1
and call D1::call_impl
. Because D1
is indeed derived form Base<D1>
, so the cast is fine at compile time.
At run time, after the cast, this
, while it is truly a D2
object is treated as if it is D1
, and the call to D1::call_impl
will modified the memory bits that are supposed to be D1::data_
, and output. In this case, these bits happened to be where D2::data_
are. I think the second d2.call_impl()
shall also be undefined behavior depending on the C++ implementation.
The point is, this code, while intensionally wrong, will give no sign of error to the user. What I am really doing in my project is that I have a CRTP base class which acts like a dispatch engine. Another class in the library access the CRTP base class' interface, say call
, and call
will dispatch to call_dispatch
which can be base class default implementation or derived class implementation. These all will work fine if the user defined derived class, say D
, is indeed derived from Base<D>
. It will raise compile time error if it is derived from Base<Unrelated>
where Unrelated
is not derived from Base<Unrelated>
. But it will not prevent user write code like above.
The user use the library by deriving from the base CRTP class and providing some implementation details. There are certainly other design alternatives that can avoid the problem of incorrect use as above (for example an abstract base class). But let's put them aside for now and just believe me that I need this design because of some reason.
So my question is that, is there any way that I can prevent the user from writing incorrect derived class as see above. That is, if user write an derived implementation class, say D
, but he derived it from Base<OtherD>
, then a compile time error shall be raised.
One solution is use dynamic_cast
. However, that is expansive and even when it works it is a run-time error.
dynamic_cast
may be expensive, but it is cheaper than trying to fix your users. – Villainagei + 1
when meaningi - 1
. This is similar. – Meador