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.
There are two vtable pointers, one per inheritance hierarchy that virtually inherits Animal . In this example, one for Mammal and one for WingedAnimal . The object size has therefore increased by two pointers, but now there is only one Animal and no ambiguity.
If you don't use virtual functions, you don't understand OOP yet. Because the virtual function is intimately bound with the concept of type, and type is at the core of object-oriented programming, there is no analog to the virtual function in a traditional procedural language.
The Diamond Problem is an ambiguity that arises in multiple inheritance when two parent classes inherit from the same grandparent class, and both parent classes are inherited by a single child class.
The answer is definitely no. The base of an idiomatic answer can be the most fundamental idea of C++: you only pay for what you use. And if you don't need virtual inheritance, you should rather not pay for it. Virtual inheritance is almost never needed.
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'
};
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.
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