The following achieves the observable behaviour you're asking for. In A
, non-virtual
fun()
run virtual fun_()
so the behaviour can be customised in B
, but anyone calling fun()
on a derived class will only see the non-polymorphic version.
#include <iostream>
using namespace std;
struct A{
void fun(){fun_();}
private:
virtual void fun_() { cout << "A\n"; }
};
struct B:public A{
void fun(){cout<<"B\n";}
private:
virtual void fun_() final { fun(); }
};
struct C:public B{
void fun(){cout<<"C\n";}
};
int main()
{
C c;B b1;
A *a=&b1;
a->fun(); //1
B *b=&c;
b->fun(); //2
c.fun(); // notice that this outputs "C" which I think is what you want
}
If using C++03, you can simply leave out the "final" keyword - it's only there to guard against further unwanted overrides of the virtual behaviour in B
-derived classes such as C
.
(You might find it interesting to contrast this with the "Nonvirtual Interface pattern" - see C++ Coding Standards by Sutter and Alexandrescu, point 39)
Discussion
A
having fun
virtual implies that overriding it in derived classes is a necessary customisation ability for derived classes, but at some point in the derivation hierarchy the choice of implementation behaviours might have narrowed down to 1 and providing a final
implementation's not unreasonable.
My real concern is that you hide A
/B
's fun()
with C::fun
... that's troubling as if they do different things then your code could be very hard to reason about or debug. B
's decision to finalise the virtual function implies certainty that there's no need for such further customisation. Code working from A*
/A&
/B*
/B&
will do one thing, while wherever a C
object's type is statically known, the behaviour may differ. Templated code is one place where C::fun
may easily be called without the template author or user being very conscious of it. To assess whether this is a genuine hazard for you, it would help to know what the functional purpose of "fun" is and how implementation might differ between A
, B
and C
....