James Kanze
11/25/2008 10:49:00 AM
On Nov 25, 10:56 am, Juha Nieminen <nos...@thanks.invalid> wrote:
> amit wrote:
> > I was reading about diamond shaped inheritance on wikipedia.
> > =======================
> > In object-oriented programming languages with multiple inheritance and
> > knowledge organization, the diamond problem is an ambiguity that
> > arises when two classes B and C inherit from A, and class D inherits
> > from both B and C. If a method in D calls a method defined in A (and
> > does not override the method), and B and C have overridden that method
> > differently, then from which class does it inherit: B, or C?
> > ======================
> That's not really the problem with diamond inheritance. You
> don't even need diamond inheritance, just multiple inheritance
> without any common base class to get that "problem". Simply
> have a function with the same name in both base classes you
> are inheriting from, and you have an ambiguity. The solution
> is that you have to explicitly specify which one you want to
> call, ie. "B::foo();" or "C::foo();"
Yes and no. The article he's quoting isn't particularly well
written, so it's not that clear what they're talking about. But
without diamond inheritance, it only becomes a problem when you
try to call the function (on a D); with diamond inheritance, it
is a problem if you try to call the function through a reference
to A, and in C++, it is a problem because the compiler doesn't
know what to put in the vtbl, which leads to a compile time
error.
Of course, the answer is the same: if the compiler doesn't know
what to do, tell it:-).
> The real problem with diamond inheritance is that if the base
> class A has a member variable, should this member variable be
> duplicated in D (once for B and once for C) or not? Should we
> consider B and C completely independent classes with nothing
> in common (in which case each has its own instance of that
> member variable from A), or should the variables from A be
> merged in D, so that they appear only once?
There seems to be a problem with vocabulary here. In C++,
unless there is virtual inheritance, there is no diamond. In
other languages, of course, inheritance may work by default like
virtual inheritance in C++. (That's the case of Java, for
example.) If the A base of B and the A base of C in a D object
have the same address, you have a diamond; if they have
different addresses, you don't.
> The problem is not really on the user code side, but on the
> compiler side.
Yes and no. The semantic is clearly different.
> What kind of technologies should the compiler use in order to
> achieve the merging? The problem is that the geometry of eg. C
> will be different if it's instantiated as itself compared to
> it being inside D, when D is instantiated. Yet eg. some
> function could take a reference of type C, and you could give
> it a true instance of C, or you could give it an instance of
> D. Both are valid parameters to it. However, that member
> variable from A is at different locations in these cases. How
> can the function in question know where it actually is?
> C++ solves this problem, but it requires for the user to make
> the decision of whether he wants the members of A to be merged
> or to be separate, and this is done by either inheriting B and
> C from A in the regular way (the members of A will become
> separate in D) or by inheriting B and C virtually from A (the
> members of A will be merged in D).
You do want to support both. If B and C are implementation
mixins, for example, it's quite possible that you do want to
different A. One can argue about the default in C++, however.
> > Question 1:
> > But it still does not answer the question raised... Lets
> > assume Base class (Class A) has a function called show().
> > Lets assume Class B and C inherit A (virtually...) and
> > override the function show(). Now Suppose class D inherits
> > both B and C (making a diamond shaped inheritance) and we
> > call show(). Which show will be called ? B's Show or C'Show
> > ?
> This has nothing to do with diamond nor virtual inheritance.
> It's just a question of ambiguity if both B and C have a
> function named the same.
Consider the following:
struct A { virtual void f() = 0 ; } ;
struct B : A { virtual void f() ; } ;
struct C : A { virtual void f() ; } ;
struct D : B, C {} ;
That's perfectly legal code, and only causes problems if you try
to call D::f(). On the other hand,
struct A { virtual void f() = 0 ; } ;
struct B : virtual A { virtual void f() ; } ;
struct C : virtual A { virtual void f() ; } ;
struct D : B, C {} ;
won't compile (at least with g++, but I think it's correct). On
the other hand, add a final virtual overrider in D (so that the
code will compile), and then write something like:
A* p = new D ;
and it's the version without the virtual inheritance which won't
compile.
> In that case you have to explicitly specify which one should
> be called by prefixing the function call with the class name,
> eg. B::show();
You don't get to specify what goes into the vtbl.
--
James Kanze (GABI Software) email:james.kanze@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