473,386 Members | 1,757 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,386 software developers and data experts.

Virtual inheritance

Hi to all, I'm facing a problem in a particularly complex inheritance
hierarchy, and I'd like to know what the standard says about it and if my
compiler is correct in what it does.

I have two consecutive layers of diamond-shaped inheritance; the first layer
is declared as using virtual inheritance, while the second one is declared
as *not* using it.

This is what I'd like to have:

Base Base
/ \ / \
D1Base D2Base D1Base D2Base
\ / \ /
Middle Middle
|| ||
D1Middle D2Middle
\ /
\ /
\ /
Last

This is what the compiler actually does:

Base
/ \
D1Base D2Base
\ /
Middle
/ \
D1Middle D2Middle
\ /
Last

If I remove all virtual inheritance, everything goes just fine; if I use it
in the first layer, there seems to be no way of disabling it afterwards.

Does the standard saying anything about this, or is it
implementation-dependant? My compiler is Visual Studio 2005.

Code sample attached.
Thanks
Massimo

Apr 30 '07 #1
12 2325
jg
On Apr 29, 6:53 pm, "Massimo" <bar...@mclink.itwrote:
Hi to all, I'm facing a problem in a particularly complex inheritance
hierarchy, and I'd like to know what the standard says about it and if my
compiler is correct in what it does.

I have two consecutive layers of diamond-shaped inheritance; the first layer
is declared as using virtual inheritance, while the second one is declared
as *not* using it.

This is what I'd like to have:

Base Base
/ \ / \
D1Base D2Base D1Base D2Base
\ / \ /
Middle Middle
|| ||
D1Middle D2Middle
\ /
\ /
\ /
Last

This is what the compiler actually does:

Base
/ \
D1Base D2Base
\ /
Middle
/ \
D1Middle D2Middle
\ /
Last
I think the object of Last will have a single subobject of Base,
not two. The other subobjects are not shared (i.e. there are
two subobjects each for D1Base, D2Base, Middle).

Base
/ / \ \
/ / \ \
/ / \ \
D1Base D2Base D1Base D2Base
\ / \ /
Middle Middle
| |/
D1Middle D2Middle
\ /
\ /
\ /
Last

JG

Apr 30 '07 #2
"jg" <jg****@gmail.comha scritto nel messaggio
news:11**********************@n76g2000hsh.googlegr oups.com...
I think the object of Last will have a single subobject of Base,
not two. The other subobjects are not shared (i.e. there are
two subobjects each for D1Base, D2Base, Middle).

Base
/ / \ \
/ / \ \
/ / \ \
D1Base D2Base D1Base D2Base
\ / \ /
Middle Middle
| |/
D1Middle D2Middle
\ /
\ /
\ /
Last
I really don't know, but don't think so, since each and every one of these
classes is (somewhat) a subclass of Base, and so inherits (or seems to
inherit) the virtual inheritance setting.

I'm actually quite sure there's only one Middle object, because the compiler
doesn't complain about method names resolution issues... while it *does*, if
inheritance is made non-virtual.

Anyway, any clue on how to obtain the desidered behaviour (if this is at all
possible)?
Massimo

Apr 30 '07 #3
On Apr 29, 9:25 pm, "Massimo" <bar...@mclink.itwrote:
"jg" <jgu...@gmail.comha scritto nel messaggionews:11**********************@n76g2000hsh .googlegroups.com...
I think the object of Last will have a single subobject of Base,
not two. The other subobjects are not shared (i.e. there are
two subobjects each for D1Base, D2Base, Middle).
Base
/ / \ \
/ / \ \
/ / \ \
D1Base D2Base D1Base D2Base
\ / \ /
Middle Middle
| |/
D1Middle D2Middle
\ /
\ /
\ /
Last

I really don't know, but don't think so, since each and every one of these
classes is (somewhat) a subclass of Base, and so inherits (or seems to
inherit) the virtual inheritance setting.

I'm actually quite sure there's only one Middle object, because the compiler
doesn't complain about method names resolution issues... while it *does*, if
inheritance is made non-virtual.

Anyway, any clue on how to obtain the desidered behaviour (if this is at all
possible)?
The problem is that every class that declares a virtual base class
shares that base class object with every other class that has declared
the same virtual base class. Therefore it is not possible to declare
D1Base and D2Base in such a way that the two pairs of D1Base and
D2Base objects share the same Base object as one another - without
also having them share the same Base object as every other pair of
D1Base and D2Base objects in the hierarchy. In other words, it is
possible to reduce the top of the current inheritance graph to a
single Base object - or three or four Base class objects - but not two
- as the graph is currently structured.

One way to remedy this problem - and to have the two Base objects at
the top of the hierarchy as desired - would be to insert a pair of
"buffer" classes, Base1 and Base2, between the Base and the D1Base and
D2Base objects. D1Base and D2Base would then each inherit from both
Base1 and Base2 as virtual base classes. The rest of the current
inheritance hierarchy would remain the same.

To illustrate. With this change the top level of the inheritance graph
would like this:

Base Base
| |
| |
Base1 Base2
| | | |
| \ / |
| \ / |
| \/ |
| /\ |
| / \ |
| / \ |
| | | |
D1Base D2Base

And the revised class declarations at the top of hierarchy would look
like:

class Base
{
int n;
};

class Base1 : public Base
{
};

class Base2 : public Base
{
};

class D1Base : public virtual Base1, public virtual Base2
{
};

class D2Base : public virtual Base1, public virtual Base2
{
};

The rest of the inheritance hierarchy would remain the same.

Greg

Apr 30 '07 #4
jg wrote:
Base
/ / \ \
/ / \ \
/ / \ \
D1Base D2Base D1Base D2Base
\ / \ /
Middle Middle
| |/
D1Middle D2Middle
\ /
\ /
\ /
Last
If you are going to draw ascii art, it would be a good
idea to use fixed-width font, wouldn't you think? That looks
like gibberish when looked with a fixed-width font.
Using variable-width font to draw ascii art is insane because
it assumes everyone else is using the exact same font as you are.
Apr 30 '07 #5
On Apr 30, 3:53 am, "Massimo" <bar...@mclink.itwrote:
Hi to all, I'm facing a problem in a particularly complex inheritance
hierarchy, and I'd like to know what the standard says about it and if my
compiler is correct in what it does.
I have two consecutive layers of diamond-shaped inheritance; the first layer
is declared as using virtual inheritance, while the second one is declared
as *not* using it.
This is what I'd like to have:
Base Base
/ \ / \
D1Base D2Base D1Base D2Base
\ / \ /
Middle Middle
|| ||
D1Middle D2Middle
\ /
\ /
\ /
Last
Which is impossible in C++.
This is what the compiler actually does:
Base
/ \
D1Base D2Base
\ /
Middle
/ \
D1Middle D2Middle
\ /
Last
That's not what it does given the code you posted. What you're
actually getting is more like.

------Base------
/ / \ \
/ / \ \
D1Base D2Base D1Base D2Base
\ / \ /
Middle Middle
|| ||
D1Middle D2Middle
\ /
\ /
\ /
Last
If I remove all virtual inheritance, everything goes just
fine; if I use it in the first layer, there seems to be no way
of disabling it afterwards.
Virtual inheritance only affects the classes which derive using
it. On the other hand, all instances of all classes which
derive from Base will share a common instance. You can't group,
with two or three different groups of classes sharing a common
instance.

What you might try is making Base, the two DnBase and Middle
templates (without changing anything else), and instantiating
them on eithre D1Middle or D2Middle. By doing this, the 2
Middle, each of the DnBase, and the two Base are formally
different types. This could result in significant code
duplication, of course.
Does the standard saying anything about this, or is it
implementation-dependant? My compiler is Visual Studio 2005.
The standard specifies very precisely what abstract graph you
should end up with. All of the compilers I have access to
(VC++, Sun CC and g++) are conform in this respect, and
generate to diagram I've given with your code.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Apr 30 '07 #6
jg
On Apr 30, 1:39 am, Juha Nieminen <nos...@thanks.invalidwrote:
jg wrote:
Base
/ / \ \
/ / \ \
/ / \ \
D1Base D2Base D1Base D2Base
\ / \ /
Middle Middle
| |/
D1Middle D2Middle
\ /
\ /
\ /
Last

If you are going to draw ascii art, it would be a good
idea to use fixed-width font, wouldn't you think? That looks
like gibberish when looked with a fixed-width font.
Using variable-width font to draw ascii art is insane because
it assumes everyone else is using the exact same font as you are.
Aha, didn't know this would have made you unhappy. Knowing
that I did not choose to do so could probably make you happy
again. :-) Yeah, your point taken !

Apr 30 '07 #7
"Greg Herlihy" <gr****@pacbell.netha scritto nel messaggio
news:11**********************@n59g2000hsh.googlegr oups.com...
To illustrate. With this change the top level of the inheritance graph
would like this:

Base Base
| |
| |
Base1 Base2
| | | |
| \ / |
| \ / |
| \/ |
| /\ |
| / \ |
| / \ |
| | | |
D1Base D2Base

And the revised class declarations at the top of hierarchy would look
like:

class Base
{
int n;
};

class Base1 : public Base
{
};

class Base2 : public Base
{
};

class D1Base : public virtual Base1, public virtual Base2
{
};

class D2Base : public virtual Base1, public virtual Base2
{
};
This way, there would be two different "n" in Base1 and Base2, and so D1Base
would have *two* n's, as would D2Base. This is not what i'm looking for... I
want D1Base to have *only one* n (here the virtual inheritance need), and
D2Base to also have *only one* n; but I need those two n's to be two
different ones when deriving from both D1Base and D2Base.

I think the only way to obtain this is to *not* derive subsequent classes
from both, but to put a couple of Middle objects inside Last as members;
this is not exactly what I needed, but it will at least work...

But I'm still curious on why the "virtual" setting for the inheritance is...
inherited, even if I've specified "virtual" only when deriving from Base,
and not when deriving subsequent classes. It just seems to have no effect on
subsequent derivations, making it actually redundant.
Massimo

Apr 30 '07 #8
"James Kanze" <ja*********@gmail.comha scritto nel messaggio
news:11**********************@q75g2000hsh.googlegr oups.com...
On Apr 30, 3:53 am, "Massimo" <bar...@mclink.itwrote:
>Virtual inheritance only affects the classes which derive using
it.
Why is it in effect when I'm sub-deriving in a non-virtual manner, then?
On the other hand, all instances of all classes which
derive from Base will share a common instance.
You can't group, with two or three different groups of classes
sharing a common instance.
Yes, I've come to understand this.
Is the "virtual" keyword on sub-derivations redundant, then?
>What you might try is making Base, the two DnBase and Middle
templates (without changing anything else), and instantiating
them on eithre D1Middle or D2Middle. By doing this, the 2
Middle, each of the DnBase, and the two Base are formally
different types.
This is a good suggestion; can you elaborate a bit? Specifically, what do
you mean by "instantiating"? Making DxMiddle a derived class of a
specialized Middle<T>? I think this wouldn't work; actually, before
semplifying it for posting, the real code involved Base, D1Base, D2Base and
Middle being template classes, and D1Middle being derived from
Middle<double>. D2Middle was derived from Middle<doubletoo, and the
purpose of D1Middle and D2Middle being different classes was exactly to be
able to derive (non-virtually!) Last from both of them, so having two
different Middle<doubleinside a Last. But I'm stuck with undesidered
virtual inheritance, so members of D1Middle and D2Middle end un accessing
the same data.
Massimo

Apr 30 '07 #9
On Apr 30, 10:33 pm, "Massimo" <bar...@mclink.itwrote:
"James Kanze" <james.ka...@gmail.comha scritto nel messaggionews:11**********************@q75g2000hsh .googlegroups.com...
On Apr 30, 3:53 am, "Massimo" <bar...@mclink.itwrote:
Virtual inheritance only affects the classes which derive using
it.
Why is it in effect when I'm sub-deriving in a non-virtual manner, then?
I don't get what you're trying to say. If you write something
like:

class A : public B {} ;

B is NOT a virtual base. Period, and regardless of anything
else in the program. There will be one instance of B for every
instance of A, always.
On the other hand, all instances of all classes which
derive from Base will share a common instance.
You can't group, with two or three different groups of classes
sharing a common instance.
Yes, I've come to understand this.
Is the "virtual" keyword on sub-derivations redundant, then?
No. Either you inherit virtually, and the keyword is necessary,
or you don't inherit virtually, and the keyword cannot be used.
What you might try is making Base, the two DnBase and Middle
templates (without changing anything else), and instantiating
them on eithre D1Middle or D2Middle. By doing this, the 2
Middle, each of the DnBase, and the two Base are formally
different types.
This is a good suggestion; can you elaborate a bit? Specifically, what do
you mean by "instantiating"?
Do you know what a template is? Do you know what it means to
instantiate it.
Making DxMiddle a derived class of a
specialized Middle<T>? I think this wouldn't work; actually, before
semplifying it for posting, the real code involved Base, D1Base, D2Base and
Middle being template classes, and D1Middle being derived from
Middle<double>. D2Middle was derived from Middle<doubletoo, and the
purpose of D1Middle and D2Middle being different classes was exactly to be
able to derive (non-virtually!) Last from both of them, so having two
different Middle<doubleinside a Last. But I'm stuck with undesidered
virtual inheritance, so members of D1Middle and D2Middle end un accessing
the same data.
The trick is to instantiate one side on D1Middle, and the other
on D2Middle.

Note that there's nothing in the rules which says that a
template has to use the instantiation type. Something like:

template< typename T >
class Base
{
// as before...
} ;

is perfectly legal. The class will behave exactly the same no
matter what type it is instantiated on, *but* it will have a
different type. Once you do this, you can then define the other
classes as:

template< typename T >
class D1Base : public virtual Base< T >
{
// as before...
} ;

template< typename T >
class D2Base : public virtual Base< T >
{
// as before...
} ;

template< typname T >
class Middle : public D1Base< T >, public D2Base< T >
{
// as before...
} ;

class D1Middle : public Middle< D1Middle >
{
// as before...
} ;

class D2Middle : public Middle< D2Middle >
{
// as before...
} ;

class Last : public D1Middle, public D2Middle
{
// as before...
} ;

This will result in the hierarchy you said you wanted, with the
exception that all of the classes on the left side will in fact
be instantiations on D1Middle, and all on the right side will in
fact be instantiations on D2Middle. (Note that this may affect
your external interface. There's no longer any such class a
Base, for example. And it typically means hoisting a lot of
code up into the headers---not necessarily something you want to
do either.)

--
James Kanze (Gabi Software) email: ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

May 1 '07 #10
"James Kanze" <ja*********@gmail.comha scritto nel messaggio
news:11**********************@n76g2000hsh.googlegr oups.com...
>I don't get what you're trying to say. If you write something
like:

class A : public B {} ;

B is NOT a virtual base. Period, and regardless of anything
else in the program. There will be one instance of B for every
instance of A, always.
That's exaclty what I would expect.
But then, if B has a virtual base C, and I do

class A1 : public B {};
class A2 : public B {};
class D: public A1,public A2 {};

As you said, B, is not a virtual base, and I should have two instances of B:
one in A1 and the other in A2. Each of these *should* contain its own base
classes, up to and including C. Why is it, then, that when I re-derive from
both of them the instance of C becomes unique? This is what is confusing me.
>Note that there's nothing in the rules which says that a
template has to use the instantiation type. Something like:

template< typename T >
class Base
{
// as before...
} ;

is perfectly legal. The class will behave exactly the same no
matter what type it is instantiated on, *but* it will have a
different type.
That's great, I'll give it a try. Thanks.
Massimo

May 1 '07 #11
On May 1, 2:31 pm, "Massimo" <bar...@mclink.itwrote:
"James Kanze" <james.ka...@gmail.comha scritto nel messaggionews:11**********************@n76g2000hsh .googlegroups.com...
I don't get what you're trying to say. If you write something
like:
class A : public B {} ;
B is NOT a virtual base. Period, and regardless of anything
else in the program. There will be one instance of B for every
instance of A, always.
That's exaclty what I would expect.
But then, if B has a virtual base C, and I do
class A1 : public B {};
class A2 : public B {};
class D: public A1,public A2 {};
As you said, B, is not a virtual base, and I should have two instances ofB:
one in A1 and the other in A2.
You do.
Each of these *should* contain its own base
classes, up to and including C.
No. When you defined B, you said that you want all instances of
B in a single hierarchy to share the same C. That's what the
virtual means in inheritance. More generally, it means that
*all* classes which inherit virtually from C share the same
instance, regardless of where they might be in the hierarchy.
Why is it, then, that when I re-derive from
both of them the instance of C becomes unique?
Because you told the compiler that that's what you wanted.

One way of looking at it is that the virtual base class is in
fact provided by the most derived class. It is the most
derived class which will call its constructor, for example, and
it is the most derived class which will determine where it is
physically located. Even if the author of the most derived
class doesn't even know it is there. So when you inherit
virtually, you are more or less saying I want a single instance
to be provided by the most derived class.
This is what is confusing me.
Just curious, but what would you expect if in addition, D
derived virtually from C, i.e.:

class B : public virtual C {} ;
class A1 : public B {} ;
class A2 : public B {} ;
class D : public A1, public A2, public virtual C {} ;

Note that you can have addional instances of C:

class B : public virtual C {} ;
class A1 : public B, public C {} ;
class A2 : public B {} ;
class D : public A1, public A2, public virtual C {} ;

This hierarchy contains two instances of C, one for all of the
virtual inheritance, and one for A1.

If you want a somewhat clearer view, try starting with:

class C
{
public:
C( std::string const& i )
{
std::cout << "C initialized by " << i << std::endl ;
}
} ;

and experimenting with different hierarchies, each time adding
an initializer for C with the class name, e.g.:

B::B() : C( "B" ) {}
A1::A1() : C( "A1" ) {}
// ...

You'll find that:

-- there's no problem specifying the initializer, as long as
there is a virtual inheritance somewhere below the class in
the hierarchy -- you don't have to specify it in the class
doing the initialization --, and

-- the constructor for C will always (without exception) be
called from the most derived class.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

May 2 '07 #12
"James Kanze" <ja*********@gmail.comha scritto nel messaggio
news:11**********************@h2g2000hsg.googlegro ups.com...
>One way of looking at it is that the virtual base class is in
fact provided by the most derived class. It is the most
derived class which will call its constructor, for example, and
it is the most derived class which will determine where it is
physically located. Even if the author of the most derived
class doesn't even know it is there. So when you inherit
virtually, you are more or less saying I want a single instance
to be provided by the most derived class.
That's a lot clearer, thanks.
Massimo

May 2 '07 #13

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

Similar topics

18
by: nenad | last post by:
Wouldn't it be nice if we could do something like this: class Funky{ public: auto virtual void doStuff(){ // dostuff } };
4
by: JKop | last post by:
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...
14
by: Bruno van Dooren | last post by:
Hi all, i am having a problems with inheritance. consider the following: class A { public: A(int i){;} };
3
by: Imre | last post by:
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...
3
by: kikazaru | last post by:
Is it possible to return covariant types for virtual methods inherited from a base class using virtual inheritance? I've constructed an example below, which has the following structure: Shape...
12
by: mijobee | last post by:
I'm very new to c++ and just writing some code to learn. I've run into a problem, with a javaish design, and want to know if there is any possible solution without modifying the design. I've read...
5
by: toton | last post by:
Hi, I want a few of my class to overload from a base class, where the base class contains common functionality. This is to avoid repetition of code, and may be reducing amount of code in binary,...
23
by: Dave Rahardja | last post by:
Since C++ is missing the "interface" concept present in Java, I've been using the following pattern to simulate its behavior: class Interface0 { public: virtual void fn0() = 0; };
0
by: =?Utf-8?B?Zmplcm9uaW1v?= | last post by:
Hi all, As I mentioned in a previous thread (see 'Dbghelp, symbols and templates' in microsoft.public.windbg), we created a powerful symbol engine using dbghelp to dump the contents of the stack...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
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
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
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
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

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.