Consider this C++ code:
#include <iostream>
using namespace std;
struct B {
virtual int f() { return 1; }
int g() { return 2; }
};
struct D1 : public B { // (*)
int g() { return 3; }
};
struct D2 : public B { // (*)
virtual int f() { return 4; }
};
struct M : public D1, public D2 {
int g() { return 5; }
};
int main() {
M m;
D1* d1 = &m;
cout << d1->f()
<< static_cast<D2&>(m).g()
<< static_cast<B*>(d1)->g()
<< m.g();
}
It prints 1225. If we make virtual inheritance, i.e. add virtual before public in lines marked with (*), it prints 4225.
- Can you explain why
1changes to4? - Can you explain meaning of
static_cast<D2&>(m)andstatic_cast<B*>(d1)? - How you are you not getting lost in this kind of combinations? Are you drawing something?
- Is it common to spot such complex settings in normal projects?
Without
virtualinheritance, there are 2 independent hierarchies of inheritance;B->D1->MandB->D2->M. So imagine 2virtualfunction tables (though this is implementation defined).When you invoke
f()withD1*, it just knows aboutB::f()and that’s it. Withvirtualinheritance, baseclass Bis delegated toMand thusD2::f()is considered as part ofclass M.static_cast<D2&>(m), is like considering object ofclass Masclass D2static_cast<B*>(d1), is like considering pointer ofclass D1asclass B1.Both are valid casts.
Since
g()is notvirtualthe function choice happens at compile-time. Had it beenvirtualthen all these casting won’t matter.Ofcourse it’s complex and at first glance if there are so many of such classes, one might get easily lost.
Not at all, it’s unusual and sometimes a code smell.