Within a C++ class hierarchy, is it possible to enforce a requirement that a particular virtual function always call its base class's implementation also? (Like the way constructors chain?)
I'm looking at a case where a deep class hierarchy has some common interface functions which each child overrides. I'd like each derived class' override to chain through to the base class. It's straightforward to do this explicitly with eg the code below, but there's the risk that someone implementing a new derived class might forget to chain through to the base.
Is there some pattern to enforce this, such that the compiler will throw an error if an override fails to chain the base?
So, in
class CAA
{
virtual void OnEvent( CEvent *e ) {
// do base implementation stuff;
}
}
class CBB : public CAA
{
typedef CAA BaseClass;
virtual void OnEvent( CEvent *e ) {
DoCustomCBBStuff();
BaseClass::OnEvent( e ); // chain to base
}
}
class CCC : public CBB
{
typedef CBB BaseClass;
virtual void OnEvent( CEvent *e ) {
Frobble();
Glorp();
BaseClass::OnEvent( e ); // chain to CBB which chains to CAA, etc
}
}
class CDD : public CCC
{
typedef CCC BaseClass;
virtual void OnEvent( CEvent *e ) {
Meep();
// oops! forgot to chain to base!
}
}
is there a way, some template trick or syntactic gimmick, to make CDD throw a more obvious error?
The way its done is the base class method is not virtual and calls a protected virtual method.
Of course, that only handles one level.
In your particular situation, a large amount of infrastructure can make it work, but it's not worth it.
The typical response is to add a comment
Put a special 'hidden' type in the Base class with a private constructor, using
friend
to ensure that only the Base can create it. This code on ideone.If there are multiple levels, this unfortunately does not guarantee that the immediate base class is called. Hence
struct E : public D;
could implementE::foo()
with a call toB:: foo
when you might prefer a call toD::foo()
.If you tried to implement D :: foo() without a return or with
return Hidden()
, you will get an error message. The only way to compile this is to usereturn B :: foo()
.There's a clang-tidy check for this: https://reviews.llvm.org/rCTE329448 (made by me, so you may address me any questions on it)
There isn't anything directly enforcing an overriding function to do anything in particular, except returning a certain type. However, if you make the base class virtual function
private
no function can call it on the base class but derived classes can override it. You then also provide apublic
function which calls the virtual function as well as a function doing the base class logic. The logic from the base class probably should go into a separate function (possibly the non-virtual forwarding function directly) to avoid executing it twice if the object actually happens to be a base object.Following a simple rule to derive through a template class it is possible.
This code yields (codepad):
Regarding some answers using
typeid
. I would never consider usingtypeid
for anything else than debugging. This is due to two things:type_info
object i.e. usingdynamic_cast
, some methodsedit:
A slightly more complex example with multiple inheritance. This one unfortunately is not solvable without explicit calls in classes that do inherit from multiple bases (mainly because it is not clear what should happen in such cases, so we have to explicitly define the behaviour).
Result is (ideone):
There is no support for this in the C++ language, but expanding on KerrekSB's comment, you could do something like this:
Then use it like this
That outputs
You have to do a little work, but you don't have to manually call the baser member function at the end of each call. Here is the live demo.