ambiguity in diamond inheritance

  • Thread starter karthikbalaguru
  • Start date
K

karthikbalaguru

Hi,

I wonder why is there an ambiguity in diamond
inheritance when we try to call the method in the
parent class from the class derived from multiple
(two)childs of the parent class.
Why C++ does not handle it internally and give us the
path to access the method in the parent class ?
Any constraints ?

Thx in advans,
Karthik Balaguru
 
D

dizzy

karthikbalaguru said:
Hi,

I wonder why is there an ambiguity in diamond
inheritance when we try to call the method in the
parent class from the class derived from multiple
(two)childs of the parent class.
Why C++ does not handle it internally and give us the
path to access the method in the parent class ?
Any constraints ?

1. there are no C++ methods, there are only member functions of various
types, let's supose you mean normal (non static, non virtual) member
function

2. if it were to be able to call it, on what instance of the common base it
should do it? Because if you have a diamond, you got 2 instances of the
common base, one though one branch of the diamond and the other through the
other so it should call the member function on which of these instances?
Thus the ambiguity

If instead, you wanted to have a single common base even if it's inherited
(indirectly) multiple times then you should look over "virtual inheritance"
in your C++ book.
 
H

happyasaclam111

Hi,

I wonder why is there an ambiguity in diamond
inheritance when we try to call the method in the
parent class from the class derived from multiple
(two)childs of the parent class.
Why C++ does not handle it internally and give us the
path to access the method in the parent class ?
Any constraints ?

Thx in advans,
Karthik Balaguru

Let's say we have four classes: A, B, C, and D
B & C both derive from A
D derives from B & C

D essentially "contains" two A sub-objects. One for the B part and
one for the C part. Consider the following code:

#include <iostream>

class A
{
int n;
public:
A(int i) : n(i) {};
virtual void f() { std::cout << "From A: " << n << std::endl; }
};

class B : public A
{
public:
B() : A(30) {};
};

class C : public A
{
public:
C() : A(50) {};
};

class D : public B, public C {};

int main()
{
D d;
d.C::f(); //prints 50
d.B::f(); //prints 30
return 0;
}

If both B & C had derived virtually from A:
class B : public virtual A {/*...*/};
class C : public virtual A {/*...*/};
Then D would only have one A sub-object. In this case, D would be
responsible for constructing A.
 
K

karthikbalaguru

1. there are no C++ methods, there are only member functions of various
types, let's supose you mean normal (non static, non virtual) member
function

2. if it were to be able to call it, on what instance of the common base it
should do it? Because if you have a diamond, you got 2 instances of the
common base, one though one branch of the diamond and the other through the
other so it should call the member function on which of these instances?
Thus the ambiguity

I understand the Diamond Problem and the solution of "Virtual
Inheritance"
that is used to overcome ambiguity.
But, i wonder why should the Diamond problem arise. This should
be taken care by C++ internally and resolved. Why C++ could not
handle it internally without asking us to do the 'virtual
inheritance'?

Thx in advans,
Karthik Balaguru
 
S

Shobhit Gupta

I understand the Diamond Problem and the solution of "Virtual
Inheritance"
that is used to overcome ambiguity.
But, i wonder why should the Diamond problem arise. This should
be taken care by C++ internally and resolved. Why C++ could not
handle it internally without asking us to do the 'virtual
inheritance'?


If c++ would automatically resolve the ambiguity, then how would you
be able to have 2 separate instances ?

Base Base
| |
| |
| |
Der1 Der2
\ /
\ /
\ /
Join


I know it would be a bad design to have such a structure, but just in
case someone wanted to have a non-diamond structure.... c++ allows
it.
 
P

Pete Becker

I understand the Diamond Problem and the solution of "Virtual
Inheritance"
that is used to overcome ambiguity.
But, i wonder why should the Diamond problem arise. This should
be taken care by C++ internally and resolved. Why C++ could not
handle it internally without asking us to do the 'virtual
inheritance'?

"The Diamond Problem" arises because the writer of a class hierarchy
didn't understand how inheritance works.

struct A
{
int i;
};

struct B : A
{
};

struct C : A
{
};

struct D : B, C
{
void f();
};

void D::f()
{
i = 3; // error: ambiguous
}

There are two separate "i" members in D. There's no way the compiler
can "handle it internally". You have to say what you mean:

void D::f()
{
B::i = 3; // OK: B's "i" member
}

If you don't want to have two "I" members in D, then the inheritance
hierarchy as written above is wrong. If the design calls for only one A
subobject, you do that by making A a virtual base everywhere. Then
there's only one "i" member in D. But note that that's a design
decision, not an implementation decision. Either you have only one A
subobject, in which case "i" is unambibuous, or you have two, and you
have to say which one you mean.
 
P

Pete Becker

If c++ would automatically resolve the ambiguity, then how would you
be able to have 2 separate instances ?

Base Base
| |
| |
| |
Der1 Der2
\ /
\ /
\ /
Join


I know it would be a bad design to have such a structure, but just in
case someone wanted to have a non-diamond structure.... c++ allows
it.

It's not a bad design if it's the correct solution to the problem. For
example, if Base is a node that can for a linked list, Join can be an
element in two lists.
 
S

Shobhit Gupta

It's not a bad design if it's the correct solution to the problem. For
example, if Base is a node that can for a linked list, Join can be an
element in two lists.


That sounds right. I was thinking of other scenarios, like having BASE
class contain some information. (In that case its better to use
composition.)
But thats something very true, if anything is a correct solution, its
probably the right design for the user.
 
H

happyasaclam111

I understand the Diamond Problem and the solution of "Virtual
Inheritance"
that is used to overcome ambiguity.
But, i wonder why should the Diamond problem arise. This should
be taken care by C++ internally and resolved. Why C++ could not
handle it internally without asking us to do the 'virtual
inheritance'?

Thx in advans,
Karthik Balaguru

Read my example above and consider this:
d.C::f() prints out 50
d.B::f() prints out 30
What should d.f() print out?

Should the compiler just guess which one you meant? Or are you asking
why non-virtual inheritance is the default?
 
K

karthikbalaguru

Read my example above and consider this:
d.C::f() prints out 50
d.B::f() prints out 30
What should d.f() print out?

Should the compiler just guess which one you meant?  Or are you asking
why non-virtual inheritance is the default?

Yes, i am asking why non-virtual inheritance is the default.

Thx in advans,
Karthik Balaguru
 
K

karthikbalaguru

Yes, i am asking why non-virtual inheritance is the default.
Apologies.
Yes, i am asking the first one - 'Should the compiler just guess
which one you meant ?' and not the second part of your post.

Thx in advans,
Karthik Balaguru
 
K

karthikbalaguru

"The Diamond Problem" arises because the writer of a class hierarchy
didn't understand how inheritance works.

struct A
{
int i;

};

struct B : A
{

};

struct C : A
{

};

struct D : B, C
{
void f();

};

void D::f()
    {
    i = 3;      // error: ambiguous
    }

There are two separate "i" members in D. There's no way the compiler
can "handle it internally".

But, Why is the compiler unable to handle it internally ?
 
J

James Kanze

But, Why is the compiler unable to handle it internally ?

Handle what? How is the compiler supposed to know which i
(B::A::i or C::A::i) you want to refer to?
 
J

James Kanze

Yes, i am asking why non-virtual inheritance is the default.

Mainly history, I suspect. Non-virtual inheritance has some
performance impacts, and is rarely needed at the application
level (and when it is needed there, it's easy to determine
where, and explicitly declare it). It's true, however, that far
too many frameworks use non-virtual inheritance where virtual
would be required: when in doubt, inheritance should be virtual
(which argues for virtual inheritance being the default).
 

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,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top