Diamond Shape Inheritance

Discussion in 'C++' started by amit, Nov 25, 2008.

  1. amit

    amit Guest

    hi,

    am new to the group. So not sure of the topic has been discussed.....

    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?
    ======================

    Now in the explanation for C++, the explanation goes as below:
    ============================
    C++ by default follows each inheritance path separately, so a D object
    would actually contain two separate A objects, and uses of A's members
    have to be properly qualified. If the inheritance from A to B and the
    inheritance from A to C are both marked "virtual" (for example, "class
    B : virtual public A"), C++ takes special care to only create one A
    object, and uses of A's members work correctly. If virtual inheritance
    and nonvirtual inheritance are mixed, there is a single virtual A and
    a nonvirtual A for each nonvirtual inheritance path to A.

    ============================

    I has the following questions:

    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 ?


    Question2:
    In the explanation it mentions the following: " a D object would
    actually contain two separate A objects".
    Now my understanding of C++ is limited. I actually thought when
    inheritance happens we have Just 1 object of derived class.
    Now as per the above statement we have 3 objects: 1 derived class
    object and 2 base class objects (possibly embedded in the derived
    class object) !!
    This kind of confused me. Is this true ?
    amit, Nov 25, 2008
    #1
    1. Advertising

  2. 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();"

    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?

    The problem is not really on the user code side, but on the compiler
    side. 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).

    > 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.

    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();

    > Question2:
    > In the explanation it mentions the following: " a D object would
    > actually contain two separate A objects".
    > Now my understanding of C++ is limited. I actually thought when
    > inheritance happens we have Just 1 object of derived class.
    > Now as per the above statement we have 3 objects: 1 derived class
    > object and 2 base class objects (possibly embedded in the derived
    > class object) !!
    > This kind of confused me. Is this true ?


    Let's forget about virtual inheritance, and let's think about the
    geometry of B. It will be like this:

    B class:
    contents of A
    additions of B

    Likewise C will be like this:

    C class:
    contents of A
    additions of C

    If we inherit D from both, its geometry will be:

    D class:
    contents of B
    contents of C
    additions of D

    But, forgetting any virtual inheritance, that's the same as:

    D class
    contents of A
    additions of B
    contents of A
    additions of C
    additions of D

    The contents of A will appear twice in D. Once for the B part and once
    for the C part.

    What virtual inheritance does is that it merges the two A parts in D
    into one. This requires internal trickery to work properly.
    Juha Nieminen, Nov 25, 2008
    #2
    1. Advertising

  3. amit

    James Kanze Guest

    On Nov 25, 8:43 am, amit <> wrote:

    > am new to the group. So not sure of the topic has been
    > discussed.....


    > I was reading about diamond shaped inheritance on wikipedia.


    In which article. The quality of Wikipedia articles is very
    variable, and many of the ones on software engineering are not
    particularly good.

    > =======================
    > 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?
    > ======================


    > Now in the explanation for C++, the explanation goes as below:
    > ============================
    > C++ by default follows each inheritance path separately, so a
    > D object would actually contain two separate A objects, and
    > uses of A's members have to be properly qualified. If the
    > inheritance from A to B and the inheritance from A to C are
    > both marked "virtual" (for example, "class B : virtual public
    > A"), C++ takes special care to only create one A object, and
    > uses of A's members work correctly. If virtual inheritance and
    > nonvirtual inheritance are mixed, there is a single virtual A
    > and a nonvirtual A for each nonvirtual inheritance path to A.
    > ============================


    > I has the following questions:


    > 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 ?


    Well, it sort of answers it indirectly, in the first part you
    quote. It's ambiguous. In C++, anything that is ambiguous is
    an error; the compiler will complain.

    > Question2:
    > In the explanation it mentions the following: " a D object
    > would actually contain two separate A objects". Now my
    > understanding of C++ is limited. I actually thought when
    > inheritance happens we have Just 1 object of derived class.
    > Now as per the above statement we have 3 objects: 1 derived
    > class object and 2 base class objects (possibly embedded in
    > the derived class object) !!


    An object can have sub-objects. In this case, the object of
    type D has two sub-objects, one of type B and one of type C, and
    each of these sub-objects has a distinct sub-object of type A.

    > This kind of confused me. Is this true ?


    Well, it would have been better if they'd have said sub-object,
    rather than object. But on the whole, yes---there are a few
    particular contexts where C++ treats base sub-objects different
    than other sub-objects (you can have a base sub-object of an
    abstract class, a base sub-object can have 0 size, etc.), but
    they are still very much objects in most senses.

    The point of course, being that without virtual inheritance, in
    C++, the inheritance structure would be:

    A A
    \ /
    B C
    \ /
    D

    and not:

    A
    / \
    B C
    \ /
    D

    (Usually, it is the latter you want, and when extending an
    interface by inheritance, it's usually best to use virtual
    inheritance.)

    --
    James Kanze (GABI Software) email:
    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
    James Kanze, Nov 25, 2008
    #3
  4. amit

    James Kanze Guest

    On Nov 25, 10:56 am, Juha Nieminen <> 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:
    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
    James Kanze, Nov 25, 2008
    #4
  5. James Kanze wrote:
    > 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.


    I didn't think of that situation. Thanks for pointing it out.
    Juha Nieminen, Nov 25, 2008
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jay Dean
    Replies:
    57
    Views:
    26,221
    Arne Vajhøj
    Dec 10, 2013
  2. Alexander Stippler

    virtual inheritance / dreaded diamond problem

    Alexander Stippler, Jul 14, 2003, in forum: C++
    Replies:
    0
    Views:
    1,876
    Alexander Stippler
    Jul 14, 2003
  3. coinjo

    DIAMOND SHAPE

    coinjo, Nov 10, 2005, in forum: C++
    Replies:
    10
    Views:
    972
    Bob Hairgrove
    Nov 12, 2005
  4. coinjo

    DIAMOND SHAPE

    coinjo, Nov 10, 2005, in forum: C++
    Replies:
    11
    Views:
    1,153
    Old Wolf
    Nov 11, 2005
  5. Replies:
    8
    Views:
    370
    John Stephens
    Sep 8, 2013
Loading...

Share This Page