Virtual inheritance...

J

JKop

I'm starting to think that whenever you derive one class from another, that
you should use virtual inheritance *all* the time, unless you have an
explicit reason not to. I'm even thinking that there shouldn't have been a
"virtual" keyword for this purpose, but instead, a "nonvirtual" keyword!


In teaching inheritance, you see the common example:


class Vehicle {}

class Car : public Vehicle {}

class Boat : public Vehicle {}


But in my opinion, this *most basic* example should be:


class Vehicle {}

class Car : virtual public Vehicle {}

class Boat : virtual public Vehicle {}


I'm thinking that one should stick in virtual inheritance *everywhere*,
unless there's an explicit reason not to. Here's one reason why:


class Vehicle {}

class Car : virtual public Vehicle {}

class Boat : virtual public Vehicle {}

class CarBoat : virtual public Car, virtual public Boat {}


Here we can see that it's preferrable to use virtual inheritance
*everywhere* unless you've an explicit reason not to.


Even going further:


class Vehicle {}

class Vehicle_Land : virtual public Vehicle {}
class Vehicle_Water : virtual public Vehicle {}
class Vehicle_Air : virtual public Vehicle {}
class Vehicle_Space : virtual public Vehicle {}

class Car : virtual public Vehicle_Land {}

class Motorcycle : virtual public Vehicle_Land {}

class Boat : virtual public Vehicle_Water {}

class Plane : virtual public Vehicle_Air {}

class Helicopter : virtual public Vehicle_Air {}

class SpaceShuttle : virtual public Vehicle_Space {}


class CarBoat : virtual public Car, virtual public Boat {}

class HelicopterMotorcycle : virtual public Helicopter, virtual public
Motorcycle{}

class UltimateVehicle : virtual public HelicopterMotorcycle, virtual public
SpaceShuttle {}


Now... "UltimateVehicle" looks like so:


-----------
| Vehicle |
-----------
^ ^ ^
___________| | |______________
/ | \
/ | \
| | |
| | |
---------------- --------------- -----------------
| Vehicle_Land | | Vehicle_Air | | Vehicle_Space |
---------------- --------------- -----------------
^ ^ ^
| | |
| | |
-------------- -------------- ----------------
| Motorcycle | | Helicopter | | SpaceShuttle |
-------------- -------------- ----------------
^ ^ ^
| | |
\ / /
\ / /
\ / /
\ / /
\ / /
------------------------ /
| MotorcycleHelicopter | /
------------------------ /
^ /
| /
\ /
\ /
\ /
\ /
\ /
-------------------
| UltimateVehicle |
-------------------



And this is exactly what we want. We've not explicit reason to make *any* of
the inheritances non-virtual.

Any thoughts on this?


One more thing, why is it called "virtual" inheritanc? I see no similarity
whatsoever between *it* and the "virtual" keyword applied to a function.


-JKop
 
I

Ivan Vecerina

JKop said:
I'm starting to think that whenever you derive one class from another,
that
you should use virtual inheritance *all* the time, unless you have an
explicit reason not to. I'm even thinking that there shouldn't have been a
"virtual" keyword for this purpose, but instead, a "nonvirtual" keyword!

Let's look at the drawbacks of using virtual inheritance
- various overheads in object size and performance will be incurred:
slower access to base class members and slower casts (including
implicit ones), and one pointer added to instances for each
base class.
- downcasting will not be possible with static_cast,
but require calls to dynamic_cast
- all subclasses will have to explicitly initialize each
parent class (except where default initialization is required).
The last issue might be the most annoying in terms of code
maintenance, and loss of encapsulation in general.

When using virtual inheritance, a class doesn't control
the initialization of its base classes anymore. This
is an unacceptable drawback in many cases.

....
In teaching inheritance, you see the common example: ....
I'm thinking that one should stick in virtual inheritance *everywhere*,
unless there's an explicit reason not to. Here's one reason why:

In teaching inheritance, most authors and instructors say
that multiple inheritance is to be avoided.

In practice, few are the object oriented frameworks that
actually use multiple inheritance (MI) in ways that require
virtual inheritance. Many languages don't even support MI.

Even when using MI, the intent is not always to share
a single instance of the common base classes.
class Vehicle {}

class Car : virtual public Vehicle {}

class Boat : virtual public Vehicle {}

class CarBoat : virtual public Car, virtual public Boat {}


Here we can see that it's preferrable to use virtual inheritance
*everywhere* unless you've an explicit reason not to.

This is the canonical example where virtual inheritance
is needed. But really, it is not such a common occurences.
Most of the uses of MI I've seen in commercial frameworks
don't need virtual inheritance.
Even going further:

class Vehicle {}
class Vehicle_Land : virtual public Vehicle {}
class Vehicle_Water : virtual public Vehicle {}
class Vehicle_Air : virtual public Vehicle {}
class Vehicle_Space : virtual public Vehicle {}
class Car : virtual public Vehicle_Land {}
class Motorcycle : virtual public Vehicle_Land {}
class Boat : virtual public Vehicle_Water {}
class Plane : virtual public Vehicle_Air {}
class Helicopter : virtual public Vehicle_Air {}
class SpaceShuttle : virtual public Vehicle_Space {}
class CarBoat : virtual public Car, virtual public Boat {}
class HelicopterMotorcycle : virtual public Helicopter, virtual public
Motorcycle{}
class UltimateVehicle : virtual public HelicopterMotorcycle, virtual
public
SpaceShuttle {} ....
And this is exactly what we want. We've not explicit reason to make *any*
of
the inheritances non-virtual.

Any thoughts on this?
Multiple inheritance here is only relevant for direct
subclasses of "Vehicle". In other derivations, the virtual
inheritance may even have undesirable effects in some
designs. One may want to keep two copies of a common
base class.
One more thing, why is it called "virtual" inheritanc? I see no similarity
whatsoever between *it* and the "virtual" keyword applied to a function.

C++ designers don't like to add new keywords, so there is a tendency
to overload their meaning. But in both cases, 'virtual' reflects
the idea of the addition of some overhead which introduces
a dynamic run-time aspect that will create some overhead ;)


The key thing is: I do not agree with your points because:
1) Multiple inheritance (in the OOP paradigm) is best avoided altogether
2) Virtual inheritance reduces encapsulation, and requires all base
classes (direct or indirect) to be initialized by each subclass.
3) Even when MI is needed, virtual inheritance is not always desirable.
4) Virtual inheritance, just like virtual functions, is associated
with an overhead which is unnecessary in most cases.


Cheers,
Ivan
 
J

JKop

Let's look at the drawbacks of using virtual inheritance
- various overheads in object size and performance will be incurred:
slower access to base class members and slower casts (including
implicit ones), and one pointer added to instances for each
base class.


Oh I just realized something (I think):


Just as how an object contains a hidden pointer to a virtual function... as
in:


class Blah
{
private:

char* t;

public:

int k;

virtual int Monkey(double k)
{
return 87;
}
};


An object of "Blah" might look something like the following in memory:

------------------------------------
| Pointer to the function "Monkey" |
------------------------------------
| t |
------------------------------------
| k |
------------------------------------


Well... similarly, if you have the following:


class Ape {}

class Monkey : virtual public Ape { int rent; }


Might an object of "Monkey" look like the following in memory?:


-----------------------------
| Pointer to the Ape object |
-----------------------------
| rent |
-----------------------------


That would explain why it's called "virtual inheritance". Am I right?


-JKop
 
I

Ivan Vecerina

JKop said:
Oh I just realized something (I think):


Just as how an object contains a hidden pointer to a virtual function...
as
in:

Actually, an object with virtual functions will (typically) store
a hidden pointer to a static *array* of virtual function pointers.
RTTI information is often stored next to the same table.

This way the array is shared by all instances of a class,
and each instance only stores a single pointer for any number
of virtual functions.
Well... similarly, if you have the following:


class Ape {}

class Monkey : virtual public Ape { int rent; }


Might an object of "Monkey" look like the following in memory?:
| Instance of "Ape" object | <--- added
-----------------------------

Also, the pointer may actually be an offset to the Ape instance.
That would explain why it's called "virtual inheritance".
Am I right?

The two are not identical, and other implementations are possible,
so this similarity does not really justify using the same name.


hth -Ivan
 
D

DaKoadMunky

Here we can see that it's preferrable to use virtual inheritance
*everywhere* unless you've an explicit reason not to.

I can't see that.

Care to explain why you think it is preferrable?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,736
Latest member
AdolphBig6

Latest Threads

Top