Is there any more benifits by virtual inheritance than resolving the"diamond problem" ?

T

thomas

virtual inheritance is usually used to resolve the "diamond problem",
I wonder if there's any more benifits.
 
J

James Kanze

virtual inheritance is usually used to resolve the "diamond problem",
I wonder if there's any more benifits.

What's the "diamond problem"? Virtual inheritance exists to
allow multiple inheritance of interfaces, where some of the
interfaces may themselves extend other interfaces. Or to
support the mixin idiom, where different implementation classes
are responsible for different aspects of the same interface.

(Arguably, virtual inheritance should be the default, since it's
generally what you want when it makes a difference.)
 
J

James Kanze

Wikipedia is your friend.

OK. The article isn't written all that clearly, but if I
understand the first section correctly, the problem would only
occur in C++ if you used virtual inheritance; virtual
inheritance creates the diamond problem, rather than solves it.

Of course, the next section, "Approaches", seems to be
dicussing something else; it certainly doesn't discuss how C++
handles the problem described immediately above. (Name hiding,
and a compiler error if this does not resolve the problem.)

In other words, the author of the article doesn't seem to know
what the "diamond problem" is himself, since he discusses two
different things under the vocable.
 
J

James Kanze

No, virtual inheritance is a solution to the diamond problem.
The diamond problem happens with multiple inheritance when the
multiple base classes have a common base class of their own.

Which only happens if there is virtual inheritance.
The problem is: Should this common base class be duplicated in
the multiple-inherited class, or should it be merged into one?

I think we have a problem of vocabulary. If the common base
class isn't merged, it isn't common---it's two distinct bases
(which perhaps happen to have the same type).
If, for example, class A has a member function named foo(),
class B inherits from A, class C inherits from A, and finally
class D inherits from both B and C, and then you create an
object of type D and call its foo() member function, what
should happen?

Exactly. Now forget about A. Remove it completely from the
example: class D inherits from both B and C, both B and C
defined foo(), and you call foo in an instance of D. Nothing
diamond-like in sight, and exactly the same problem.
(Obviously, the author of the Wikipedia article doesn't really
understand what he is talking about. Happens sometimes.) And
even with A, if the problem occurs, inheriting virtually doesn't
change anything.
Moreover, if a function in B calls a function in A which
modifies some member variable of A, and some other function in
C calls that same function in A, what should happen?

A shouldn't have any member variables:). (Seriously, it is
*usually* a design error if A has any state. But of course,
like most rules, there are occasional exceptions.)

More importantly, what should happen depends on the design, but
most often, what should happen is that there is only one
instance of A. In other words, you should have a diamond. (In
which case, the diamond isn't the problem, it's the solution.)
Should both the B and C calls cause the *same* member variable
to be modified, or should these two members be separate (so
that B has its own state, separate from C which has its own)?

It depends on the design. Any reasonably good OO language will
support both.
Suppose you have an object of type D. If some function
somewhere expects an object of type A, and a member function
of B gives 'this' to it, what should happen? Likewise if a
member function of C calls that function taking an object of
type A. Should they pass their common A sub-object, or should
they pass separate A sub-objects? (This can make a huge
difference not only on the state of the A part of the object,
but because A might have some virtual function which both B
and C implement.)

What they should pass isn't really the question. The question
is whether they should have separate sub-objects. Most of the
time, at least in the case of public inheritance, they
shouldn't; sometimes they should. Whatever the case, however, C
should pass the pointer to its A sub-object, and not that of B's
sub-object. (C shouldn't even know that B exists.) If they're
common (a diamond shaped hierarchy), then the address of C's
sub-object will be the same as that of B's sub-object. If
they're different (no diamond), then of course, C should use the
address of its sub-object.

And none of this, IMHO, deserves any name with the word
"problem" in it. (But maybe I'm influenced by the fact that my
first OO language was C++, where you can choose which ever
solution the design requires.)
Not using virtual inheritance is taking one stance (B and C
should be separate and have no common base), while using
virtual inheritance is taking another (their bases should be
merged). Thus virtual inheritance offers one solution to the
problem.

First, there's no problem; your design determines whether you
need a diamond or not. And the choice between virtual and
non-virtual inheritance allows choosing the appropriate solution
for the design.
It discusses how some languages supporting multiple
inheritance deal with the problems.

It doesn't say anything about the "problem" (function call
ambiguity) presented in the first section. The "Approaches"
section does present more or less the possibilities different
languages offer with regards to creating more or less complex
inheritance hierarchies. (On rereading it, he does seem to
address the ambiguity question in his discussion of some of the
other languages. But when he mentions it, he doesn't say
anything about instances.)

The duplication (or not) and the function call ambiguity are two
separate, orthogonal issues.
I think it's you who is not understanding what the problem is
(which, quite frankly, I find quite surprising).

The reason I don't understand what it is is that so many people
present so many different opinions about what it is. And that
to date, no one has shown me anything which could be considered
a problem with the diamond inheritance hierarchy; the problem
could be (in some other languages) that they don't support the
diamond hierarchy---a no-diamond problem. And the article
confused me even further, because the author mixes unrelated
issues.
 
B

Balog Pal

James Kanze said:
Which only happens if there is virtual inheritance.

That is the strange view.
You design things in abstract, and (say in UML) discover that you have
ostream and istream that work fine in solo, and need iostream, that merry
them. But they already have that ios as base class, that *shall* be common
in iostream. (if actually drawn the usual way looks like a rombus...).

The design with the requirements is far from any kind of implementation, so
it can hardly be created from existance of virtual inheritance. IIRC
virtual inheritance's entering C++ was massively motivated by that iostream
library design, without which it could not be implemented to that spec.
I think we have a problem of vocabulary. If the common base
class isn't merged, it isn't common---it's two distinct bases
(which perhaps happen to have the same type).

The class is clearly common -- the question is whether the object is common
or not.
Just often the "bace class sub-object" is in practice abbreviated as "base
class" then it can create this very confusion.



A shouldn't have any member variables:). (Seriously, it is
*usually* a design error if A has any state.

If A is just interface there's obvoisly no state. In case of ios it very
likely has state.

In old days of C++ we had many Object - based hierarchies. With Object
having RTTI primitives, and possibly factory support. And most anything was
supposed to derive from Object or some of its descendant provided by the
framework. Brobably had some state too. Though MI was pretty hosed with
those beasts unless one discovered that deriving from object is better
dismissed ;-))
It depends on the design. Any reasonably good OO language will
support both.

Ah, do we have abdundance of reasonably good OO languages?
What they should pass isn't really the question. The question
is whether they should have separate sub-objects. Most of the
time, at least in the case of public inheritance, they
shouldn't; sometimes they should.

And for private inheritance they most likely shouldn't.
First, there's no problem; your design determines whether you
need a diamond or not. And the choice between virtual and
non-virtual inheritance allows choosing the appropriate solution
for the design.

Certainly provided that your supposedly OO-supporting language allows a
solutio that looks like the model. If not, you have quite a problem don't
you? ;-)

The reason I don't understand what it is is that so many people
present so many different opinions about what it is. And that
to date, no one has shown me anything which could be considered
a problem with the diamond inheritance hierarchy; the problem
could be (in some other languages) that they don't support the
diamond hierarchy---a no-diamond problem.

Hm, that looks like another vocabulary issue.
 
G

Gert-Jan de Vos

virtual inheritance is usually used to resolve the "diamond problem",
I wonder if there's any more benifits.

You can use it to prevent further derivation from a class:

class FinalHelper
{
protected:
FinalHelper() {}
};

class MyFinal : virtual private FinalHelper
{
};

MyFinal can not be derived from: a derived class's constructor would
be responsible for constructing FinalHelper but FinalHelper is not
accessible there.

This is just a side effect of the rules for virtual base class
construction though.
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top