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?
This is hard to answer in this abstract way, because it all depends on what the classes are doing and how you use them.
Having virtual inheritance means that your two middle classes will share the same
Base
. Is that what you want?There is no language rule against actually having two separate
Base
classes in the hierarchy. It's just a bit harder to call member functions, because you have to explicitly indicate which copy you want to call by prefixing the function namep->NewClass::base_function()
orp->OldClass::base_function();
. That works if sharingBase
data is not what you need.And like Serge says, if some other class only inherits one
Base
, it will still just contain one Base.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.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:
vs
Also, the initializer behaviour is different, because the initializer for
A
inB
is ignored ifB
is not the most derived class:If you had non-virtual inheritance here (which would force you to remove the
A
initializer in theC
constructor, the third line would outputA2B1C0
.According to the standard, virtual inheritance is exactly the same as non virtual one except that only one single instance of the virtualy inherited class exists in the derived object.
So in nothing in original code had multiple inheritance on classes derived from
Base
, changing the inheritance ofBase
to be virtual should not change behaviour. But you must consult of build the class hierachy to be sure of it.Refs from n4096 draft:
And except from the examples following that paragraph, I could find no other reference to virtual inheritance in [class.mi].