I'm working on a huge project that I didn't start. My task is to add some additional functionality to what already is there. I'm in a situation where I have to use virtual inheritance because I have a diamond model. The situation is depicted in the following illustration:
Base class
/ \
/ \
My new class A class that was there before (OldClass)
\ /
\ /
\ /
\ /
My other new class
For this to work, both the classes in the middle have to inherit from the base through public virtual
instead of just public
. So:
class OldClass: public BaseClass {}
has to become:
class OldClass: public virtual BaseClass {}
Since this project is really huge and I'm working on a small part of it, I don't want to break it by doing this. My adhoc tests worked and the program seems to work fine, but I'm still skeptic.
So my question is: What side effects and consequences should I expect by adding the virtual
keyword? Is there anything to worry about?
The immediate consequence is that for regular inheritance, derived classes invoke the constructor of the immediate base, while for virtual inheritance, the most derived class (i.e. the one being instantiated directly) does, as this is the only place that would know all the virtual bases.
Compare:
struct A { A(int) { } };
struct B : A { B(int i) : A(i) { } };
struct C : B { C(int i) : B(i) { } };
vs
struct A { A(int) { } };
struct B : virtual A { B(int i) : A(i) { } };
// wrong: struct C : B { C(int i) : B(i) { } };
struct C : B { C(int i) : A(i), B(i) { } }; // correct
Also, the initializer behaviour is different, because the initializer for A
in B
is ignored if B
is not the most derived class:
struct A { A(int i) { cout << 'A' << i; } };
struct B : virtual A { B(int i) : A(i+1) { cout << 'B' << i; } };
struct C : B { C(int i) : A(i+1), B(i+1) { cout << 'C' << i; } };
A a(0); // prints A0
B b(0); // prints A1B0
C c(0); // prints A1B1C0
If you had non-virtual inheritance here (which would force you to remove the A
initializer in the C
constructor, the third line would output A2B1C0
.
In addition to what Simon Richter said about calling constructors, using virtual inheritance means that you should be a bit more careful with your casts: You need to use dynamic_cast<>
whenever you downcast a pointer in a hierarchy that includes virtual inheritance, as the relative offset between the base object and the goal type of the cast depends on the concrete actual type of the object. Other than that, everything else should work as expected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With