473,390 Members | 1,686 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,390 software developers and data experts.

Heavy use of virtual MI


Hi!

I've got some questions regarding heavy use of virtual inheritance.

First, let's see a theoretical situation, where I might feel tempted to
use a lot of virtual inheritance.

Let's suppose, we're creating a little strategy game. In our game,
there are Units. A Unit can be either a Human, or a Vehicle. Obviously,
Human and Vehicle are subclasses of Unit.

Now let's suppose that we'd like to use protocol classes, to separate
interface from implementation as much as possible. So we create a
UnitIntf class, and a UnitImpl derived from it. Likewise, we have
HumanIntf and HumanImpl. HumanIntf, besides inheriting from HumanIntf,
should also inherit from UnitImpl. Our class hierarchy now looks like
this (let's forget about Vehicles for now):

UnitIntf
/ \
UnitImpl HumanIntf
\ /
HumanImpl

Furthermore, let's suppose, that we want to seprate functionality
common to most strategy games from functionality specific to our
current game, so that we may easily reuse the common parts in our next
game (or in another one in parallel development). That is, we want to
create a GameEngine layer, and on top of that, a Game layer. So, in our
Engine, we have Unit and Human, interfaces and implementations. In
Game, we have to introduce some Game-specific stuff on the Unit level,
and then some other game-specific things on the Human level. So we will
need GameUnit and GameHuman classes. If we still stick to the interface
/ implementation separation, then we'll have the following classes and
inheritances:

EngineUnitIntf
EngineUnitImpl: EngineUnitIntf
EngineHumanIntf: EngineUnitIntf
EngineHumanImpl: EngineHumanIntf, EngineUnitImpl
GameUnitIntf: EngineUnitIntf
GameUnitImpl: GameUnitIntf, EngineUnitImpl
GameHumanIntf: GameUnitIntf, EngineHumanImpl
GameHumanImpl: GameHumanIntf, GameUnitImpl, EngineHumanImpl

I won't even try to draw this. (Actually, it would be easy in 3d: it's
a nice cube. On one axis, there's Engine / Game, on the other Unit /
Human, and the third Intf / Impl.)

Such design would make heavy use of virtual inheritance. In fact, _all_
the inheritances should be virtual (at least, if we suppose that Human
may have further subclasses).

Although the hierarchy may seem complicated at first, I think it can be
get used to, and once one's used to it, it can even be convenient to
use.

However, I'm not sure how much run-time overhead this would cause.

How is virtual inheritance typically implemented on current compilers?

Am I overusing inheritance here? What design alternatives are there to
create something similar? What's the performance comparison between
protocol classes vs. the pimpl idiom?

Thanks,

Imre

Jul 1 '06 #1
3 1686
Imre wrote:
I've got some questions regarding heavy use of virtual inheritance.

First, let's see a theoretical situation, where I might feel tempted to
use a lot of virtual inheritance.
What you're describing is not virtual inheritance -- that's something
else entirely. Look it up. What you're describing is inheritance from
abstract classes -- i.e., those with only pure virtual functions
(analogous to Java interfaces).
UnitIntf
/ \
UnitImpl HumanIntf
\ /
HumanImpl

EngineUnitIntf
EngineUnitImpl: EngineUnitIntf
EngineHumanIntf: EngineUnitIntf
EngineHumanImpl: EngineHumanIntf, EngineUnitImpl
GameUnitIntf: EngineUnitIntf
GameUnitImpl: GameUnitIntf, EngineUnitImpl
GameHumanIntf: GameUnitIntf, EngineHumanImpl
GameHumanImpl: GameHumanIntf, GameUnitImpl, EngineHumanImpl

I won't even try to draw this. (Actually, it would be easy in 3d: it's
a nice cube. On one axis, there's Engine / Game, on the other Unit /
Human, and the third Intf / Impl.)
There are some obvious questions to be asked about such a design, on
the face of it. Regardless of your questions about efficiency, there
are OOD reasons not to have a million interfaces and a million levels
of hierarchy in a complex lattice. It's not just that it's difficult
to understand, though that can be part of it. It's inflexible. Many
small interfaces are good, but when you start having things like
parallel inheritance hierarchies of interfaces and implementations, it
really begins to not pay for itself. The poor chump at the bottom of
the hierarchy is tightly coupled to all of its parents and has way too
many responsibilities, as a result of having to support so many
interfaces. Just because something is a single sprite on a screen
doesn't mean that all its behavior need live within a single class.
For example, a Unit may have an x and y position, but the movement code
could be entirely separate, and just update x and y once it's figured
out where to move.
Such design would make heavy use of virtual inheritance. In fact, _all_
the inheritances should be virtual (at least, if we suppose that Human
may have further subclasses).
Subsituting again what you mean for what you said, I'll point out that
in C++, once a member function is virtual, it can never *stop* being
virtual farther down the inheritance chain. This isn't obvious,
because the virtual keyword is optional after the first use. Me, I'd
perhaps prefer if it were mandatory.
Although the hierarchy may seem complicated at first, I think it can be
get used to, and once one's used to it, it can even be convenient to
use.
Any design that you feel you must make excuses for and defend is
unlikely to be a good design. It's not just a question of how hard it
is to use, it's a question of how hard it is to change -- as with any
design.
However, I'm not sure how much run-time overhead this would cause.

How is virtual inheritance typically implemented on current compilers?
The rule of thumb is that every virtual function call costs about as
much as one extra pointer dereference at runtime, compared to a
non-virtual function call. If you want to know more about the
mechanism, STFW for terms like "virtual table," "virtual dispatch."
"dynamic binding," etc.
Am I overusing inheritance here? What design alternatives are there to
create something similar?
Quite possibly you are, yes. PreferCompositionToInheritance and obey
the SingleResponsibilityPrinciple. I made WikiWords out of those
because they're probably pages on c2, and you can go look there for
elaboration.
What's the performance comparison between
protocol classes vs. the pimpl idiom?
I assume by "protocol classes" you mean abstract interfaces. In which
case, this is apples-to-oranges. The two idioms do not solve similar
problems, and so comparing them is meaningless.

Luke

Jul 2 '06 #2

First, thanks for your answers. I've got some more questions though, if
you don't mind.

Luke Meyers wrote:
Imre wrote:
First, let's see a theoretical situation, where I might feel tempted to
use a lot of virtual inheritance.

What you're describing is not virtual inheritance -- that's something
else entirely. Look it up. What you're describing is inheritance from
abstract classes -- i.e., those with only pure virtual functions
(analogous to Java interfaces).
Not neccessarily. Yes, some of the classes involved are abstract base
classes, but there are also some base classes that provide
implementation. For example, GameUnitImpl would be likely to inherit
some implementation from EngineUnitImpl. Also, Human inherits
implementation from Unit.
There are some obvious questions to be asked about such a design, on
the face of it. Regardless of your questions about efficiency, there
are OOD reasons not to have a million interfaces and a million levels
of hierarchy in a complex lattice. It's not just that it's difficult
to understand, though that can be part of it. It's inflexible. Many
small interfaces are good, but when you start having things like
parallel inheritance hierarchies of interfaces and implementations, it
really begins to not pay for itself. The poor chump at the bottom of
the hierarchy is tightly coupled to all of its parents and has way too
many responsibilities, as a result of having to support so many
interfaces. Just because something is a single sprite on a screen
doesn't mean that all its behavior need live within a single class.
For example, a Unit may have an x and y position, but the movement code
could be entirely separate, and just update x and y once it's figured
out where to move.
Yes, I agree with you, and here I'd use some kind of component based
design.

However, the original example was a bit different. I can see how to
factor out the movement code into a separate, contained object, but I
can't see how to do that when inheritance is used to separate the
abstract interface from the implementation (UnitIntf / UnitImpl), or to
separate different layers (EngineUnit / GameUnit).
Maybe the Unit / Human inheritance could be removed, if all units in
the game are instances of Unit, and they differ only in the components
they contain (eg. a vehicle has a WheelManager component added to it,
while a human doesn't), but... it feels a bit, well, unnatural to me.
PreferCompositionToInheritance and obey
the SingleResponsibilityPrinciple.
Generally I try to follow these rules (especially the one about single
responsibilities), but in the original example I'm not sure how I
should do it.

Thanks,

Imre

Jul 3 '06 #3
Imre wrote:
What you're describing is not virtual inheritance -- that's something
else entirely. Look it up. What you're describing is inheritance from
abstract classes -- i.e., those with only pure virtual functions
(analogous to Java interfaces).

Not neccessarily. Yes, some of the classes involved are abstract base
classes, but there are also some base classes that provide
implementation. For example, GameUnitImpl would be likely to inherit
some implementation from EngineUnitImpl. Also, Human inherits
implementation from Unit.
Yes, of course -- the point was that "virtual inheritance" means
something else entirely, and you consistently used that term
incorrectly, so you should look it up and understand it to avoid that
mistake in the future.
However, the original example was a bit different. I can see how to
factor out the movement code into a separate, contained object, but I
can't see how to do that when inheritance is used to separate the
abstract interface from the implementation (UnitIntf / UnitImpl), or to
separate different layers (EngineUnit / GameUnit).
Maybe the Unit / Human inheritance could be removed, if all units in
the game are instances of Unit, and they differ only in the components
they contain (eg. a vehicle has a WheelManager component added to it,
while a human doesn't), but... it feels a bit, well, unnatural to me.
PreferCompositionToInheritance and obey
the SingleResponsibilityPrinciple.

Generally I try to follow these rules (especially the one about single
responsibilities), but in the original example I'm not sure how I
should do it.
It's really impossible to say, since all you ever did was list the
interfaces, not saying anything about the responsibilities involved.
The movement example was my best guess at the sort of thing you might
mean. If you want to know whether you've grouped your responsibilities
appropriately (or rather, not grouped them, but not divided them
either), you'll have to say what they are.

Luke

Jul 3 '06 #4

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Ray Paseur | last post by:
My client is a financial services firm with very large email requirements. Hundreds of messages per day both in and out, with attachments in the 1MB to 10MB range. Can anyone suggest a US-based...
0
by: Kayra Otaner | last post by:
Hi all, I want to get your opinions on how to increase available/free memory and performance on a heavy volume database server. I have MySQL 4.0.13 running on RH 7.2 replicated to another RH...
9
by: Jack | last post by:
Hello I have a library of calculationally intensive classes that is used both by a GUI based authoring application and by a simpler non-interactive rendering application. Both of these...
3
by: John Wells | last post by:
A manager friend of mine sent me the following concern. He's preparing to shift to Postgresql from a proprietary DB and 4gl system: ----------- To that end, I've also started studying up on...
4
by: Michiel Alsters | last post by:
Hello everybody, I hope anybody can help me. I'll try to give a brief overview of my problem. I have running a program that performs a heavy calculation. To give the user feedback what the...
10
by: roygon | last post by:
Hello, I have a C# application that runs a relatively complex simulation which, on a typical computer, could take up to 10 seconds. I am now trying to port this application over to ASP.NET so...
6
by: Chris Burnley | last post by:
We're seeing very strange behaviour with db2 under heavy load. We're running our system in GMT and the timezone never changes for British Summer Time. Basically the thing we're doing is (using...
6
by: JimLad | last post by:
Hi, We have a major ASP app that we are in the process of upgrading to ASP.NET 1.1 and probably on to ASP.NET 2.0 in the middle of next year. (We will also be upgrading to SQL2K5 at the same...
25
by: jwrweatherley | last post by:
I'm pretty new to python, but am very happy with it. As well as using it at work I've been using it to solve various puzzles on the Project Euler site - http://projecteuler.net. So far it has not...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.