I have a plain old CRPT (please don't get distracted by access restrictions - the question is not about them):
template<class Derived>
class Base {
void MethodToOverride()
{
// generic stuff here
}
void ProblematicMethod()
{
static_cast<Derived*>(this)->MethodToOverride();
}
};
that is as usual intended to be used like this:
class ConcreteDerived : public Base<ConcreteDerived> {
void MethodToOverride()
{
//custom stuff here, then maybe
Base::MethodToOverride();
}
};
Now that static_cast
bothers me. I need a downcast (not an upcast), so I have to use an explicit cast. In all reasonable cases the cast will be valid since the current object is indeed of the derived class.
But what if I somehow change the hierarchy and the cast now becomes invalid?
May I somehow enforce a compile-time check that an explicit downcast is valid in this case?
When you do something like below:
You can create objects of the
class
(derived or base). But if you try calling the function, it gives compilation error related tostatic_cast
only. IMHO it will satisfy all practical scenarios.If I correctly understood the question, then I feel the answer is in your question itself. :)
At compile-time you can only check the static types, and that's what
static_cast
already does.Given a
Base*
, it is only, and can only be, known at run-time what its dynamic type is, that is, whether it actually points to aConcreteDerived
or something else. So if you want to check this, it has to be done at runtime (for example by usingdynamic_cast
)To expand on what @Bo Persson said, you can do a compile time check in said constructor using for example Boost.TypeTraits or C++0x/11
<type_traits>
:Full example on Ideone.
For extra safety, you could add a protected constructor to Base, to make sure that something is derived from it. Then the only problem would be for the really stupid:
but that should be caught by the first code review or test case.
It seems that there exists a way to check CRPT correctness at compile time.
By making Base abstract (adding some pure virtual method to Base) we guarantee that any Base instance is a part of some derived instance.
By making all Base constructors private we can prevent undesirable inheritance from Base.
By declaring Derived as friend of Base we allow the only inheritance expected by CRPT.
After this, CRPT downcast should be correct (since something is inherited from base and this "something" may be only Derived, not some other class)
Perhaps for practical purpose the first step (making Base abstract) is redundant since successful static_cast guaranties that Derived is somewhere in the Base hierarchy. This allows only an exotic error if Derived is iherited from
Base <Derived>
(as CRPT expects) but at the same time Derived creates another instance ofBase <derived>
(without inheritance) somewhere in Derived code (it can, because it is a friend). However, I doubt that someone may accidentally write such exotic code.