I'm reading about inheritance and I have a major issue that I haven't been able to solve for hours:
Given a class Bar
is a class with virtual
functions,
class Bar
{
virtual void Cook();
};
What is the different between:
class Foo : public Bar
{
virtual void Cook();
};
and
class Foo : public virtual Bar
{
virtual void Cook();
};
? Hours of Googling and reading came up with lots of information about its uses, but none actually tell me what the difference between the two are, and just confuse me more.
Virtual inheritance is only relevant if classes are to inherit from
Foo
. If I define the following:
class B {};
class L : virtual public B {};
class R : virtual public B {};
class D : public L, public R {};
Then the final object will only contain one copy of B
, shared by both
L
and R
. Without the virtual
, an object of type D
would contain
two copies of B
, one in L
, and one in R
.
There is some argument that all inheritance should be virtual (because
in the cases where it makes a difference, that is what you want most of
the time). In practice, however, virtual inheritance is expensive, and
in most cases, not necessary: in a well designed system, most
inheritance will simply be of a concrete class inheriting from one or
more "interfaces"; such a concrete class is usually not designed to be
derived from itself, so there is no problem. But there are important
exceptions: if, for example, you define an interface, and then
extensions to the interface, the extensions should inherit virtually
from the base interface, since a concrete implementation could want to
implement several extensions. Or if you are designing mixins, where
certain classes only implement part of the interface, and the final
class inherits from several of these classes (one per part of the
interface). In the end, the criteron as to whether to inherit virtually
or not isn't too difficult:
if the inheritance isn't public, it probably shouldn't be virtual
(I've never seen an exception), otherwise
if the class is not designed to be a base class, there's no need for
virtual inheritance, otherwise
the inheritance should be virtual.
There are a few exceptions, but the above rules err on the side of
safety; it's usually "correct" to inherit virtually even in cases where
the virtual inheritance isn't necessary.
One final point: a virtual base must always be initialized by the most
derived class, not the class that directly inherits (and declares that
the inheritance is virtual). In practice, however, this is a non-issue.
If you look at the cases where virtual inheritance makes sense, it is
always a case of inheriting from an interface, which will contain no
data, and thus have (only) a default constructor. If you find yourself
inheriting virtually from classes with constructors which take
arguments, it's time to ask some serious questions about the design.
Functionality wise there is not much difference between the 2 versions. With the case of virtual
inheritance, every implementation generally adds a (vptr
like) pointer (same as in the case of virtual
functions). Which helps to avoid multiple base class copies generated due to multiple inheritance (the diamond inheritance problem)
Also, virtual
inheritance delegates the right to call the constructor of its base class. For example,
class Bar;
class Foo : public virtual Bar
class Other : public Foo // <--- one more level child class
So, now Bar::Bar()
will be called directly from Other::Other()
and also will be placed at the first place among other base classes.
This delegation feature helps in implementing a final class
(in Java) functionality in C++03:
class Final {
Final() {}
friend class LastClass;
};
class LastClass : virtual Final { // <--- 'LastClass' is not derivable
...
};
class Child : public LastClass { // <--- not possible to have object of 'Child'
};
In this case, no difference. Virtual inheritance is related to sharing superclass subobjects instances by derived classes
struct A
{
int a;
};
struct B : public virtual A
{
int b;
}
struct C : public virtual A
{
int c;
};
struct D : public B, public C
{
};
There's a single copy of the member variable a
in the instance of D
; If A
was not a virtual base class, there would be two A
subobjects in instance of D
.
Virtual function is a function that will probably have different implementation in derived class (although it's not a must).
In your last example is virtual inheritance. Imagine a case where you have two classes (A and B) derived from a base class (let's call it 'Base'). Now imagine a third class C derived from A and B. Without virtual inheritance, the C would contain two copies of 'Base'. That could lead to ambiguity while compiling. The important thing in virtual inheritance is that the parameters for the 'Base' class constructor (if any) MUST be provided in the class C, because such calls from A and B will be ignored.