Multiple inheritance ambiguous base class - c++

Consider the code
struct Base{};
struct Derived: public Base{};
struct A: public Base{};
struct B: public A, public Base{};
struct C: public A, public Derived{}; // why no ambiguity here?
int main() {}
The compiler (g++5.1) warns that
warning: direct base 'Base' inaccessible in 'B' due to ambiguity struct B: public A, public Base{};
I understand this, Base is duplicated in B.
Why is there no warning for C? Doesn't C inherit from both A and Derived, which both inherit from Base?
Why adding virtual
struct Derived: virtual Base{};
results now in both B and C emitting warnings, live on Wandbox
warning: direct base 'Base' inaccessible in 'B' due to ambiguity struct B: public A, public Base{};
warning: direct base 'Base' inaccessible in 'C' due to ambiguity struct C: public A, public Derived{};

In B, it's impossible to refer to members of the Base subobject inherited directly. Consider:
struct Base {
int x;
};
struct B: public A, public Base {
void foo() {
int& x1 = A::x; // OK
int& x2 = x; // ambiguous
// no way to refer to the x in the direct base
}
};
In C this is not a problem. Both x's can be referred to using qualified names:
struct C: public A, public Derived {
void foo() {
int& x1 = A::x; // OK
int& x2 = Derived::x; // OK
}
};
So the warning you get is one that only makes sense when a direct base is also inherited through another path.
For your second question, I couldn't reproduce the warning with C on Coliru with g++-5.1.

There are no ways to access unambiguously to Base members in "B" whereas it's possible in "C", as illustrated in the following code:
#include <iostream>
using namespace std;
struct Base
{
void print()
{
cout << "Base" << endl;
}
};
struct Derived : public Base {};
struct A : public Base
{
void print()
{
cout << "A" << endl;
}
};
struct B : public A, public Base
{
void print()
{
A::print();
//error (ambiguous), no way to access to Base::print => warning
//Base::print();
}
};
struct C : public A, public Derived
{
void print()
{
A::print();
Derived::print(); // Not Ambiguous, it's the Base inherited by 'Derived' which is used.
// Still an error but you can access print indirectly through "Derived" => no warning needed
//Base::print();
}
};
int main()
{
B b;
b.print();
C c;
c.print();
return 0;
}

Related

How does A*(pointing to a C) vs a C influence the ambiguity? [duplicate]

Consider the code
struct Base{};
struct Derived: public Base{};
struct A: public Base{};
struct B: public A, public Base{};
struct C: public A, public Derived{}; // why no ambiguity here?
int main() {}
The compiler (g++5.1) warns that
warning: direct base 'Base' inaccessible in 'B' due to ambiguity struct B: public A, public Base{};
I understand this, Base is duplicated in B.
Why is there no warning for C? Doesn't C inherit from both A and Derived, which both inherit from Base?
Why adding virtual
struct Derived: virtual Base{};
results now in both B and C emitting warnings, live on Wandbox
warning: direct base 'Base' inaccessible in 'B' due to ambiguity struct B: public A, public Base{};
warning: direct base 'Base' inaccessible in 'C' due to ambiguity struct C: public A, public Derived{};
In B, it's impossible to refer to members of the Base subobject inherited directly. Consider:
struct Base {
int x;
};
struct B: public A, public Base {
void foo() {
int& x1 = A::x; // OK
int& x2 = x; // ambiguous
// no way to refer to the x in the direct base
}
};
In C this is not a problem. Both x's can be referred to using qualified names:
struct C: public A, public Derived {
void foo() {
int& x1 = A::x; // OK
int& x2 = Derived::x; // OK
}
};
So the warning you get is one that only makes sense when a direct base is also inherited through another path.
For your second question, I couldn't reproduce the warning with C on Coliru with g++-5.1.
There are no ways to access unambiguously to Base members in "B" whereas it's possible in "C", as illustrated in the following code:
#include <iostream>
using namespace std;
struct Base
{
void print()
{
cout << "Base" << endl;
}
};
struct Derived : public Base {};
struct A : public Base
{
void print()
{
cout << "A" << endl;
}
};
struct B : public A, public Base
{
void print()
{
A::print();
//error (ambiguous), no way to access to Base::print => warning
//Base::print();
}
};
struct C : public A, public Derived
{
void print()
{
A::print();
Derived::print(); // Not Ambiguous, it's the Base inherited by 'Derived' which is used.
// Still an error but you can access print indirectly through "Derived" => no warning needed
//Base::print();
}
};
int main()
{
B b;
b.print();
C c;
c.print();
return 0;
}

Why is constructor of a grand parent deleted in this case?

The compiler is complaining the constructor of D is deleted because of ill forming why ?
#include<iostream>
using namespace std;
class A
{
int x;
public:
A(int i) { x = i; }
void print() { cout << x; }
};
class B: virtual public A
{
public:
B():A(10) { }
};
class C: virtual public A
{
public:
C():A(10) { }
};
class D: public B, public C {
};
int main()
{
D d;
d.print();
return 0;
}
Output
main.cpp:37:4: error: use of deleted function 'D::D()' D d;
^ main.cpp:32:7: note: 'D::D()' is implicitly deleted because the default definition would be ill-formed: class D: public B, public C {
^
Due to the rules for initialization of virtual base classes,
class D: public B, public C {
};
is equivalent to:
class D: public B, public C {
public:
D() : A(), B(), C() {}
};
That's why you cannot create in instance of D.
Solution 1
Change A so it has a default constructor.
class A
{
int x;
public:
A(int i = 0) { x = i; }
void print() { cout << x; }
};
Solution 2
Change D to:
class D: public B, public C {
public:
D() : A(0), B(), C() {}
};
or a simpler version,
class D: public B, public C {
public:
D() : A(0) {}
};
That's because D inherits from A indirectly using virtual. A doesn't have a parameterless constructor so a compiler-generated constructor for D can't be made.
Note: this is mostly just adding a reference to the standard, in case anybody might care (but as usual for him, #R. Sahu's answer is quite accurate).
The standard specifies ([class.base.init]/13) that:
In a non-delegating constructor, initialization proceeds in the
following order:(13.1) — First, and only for the constructor of the
most derived class (6.6.2), virtual base classes are initialized in
the order they appear on a depth-first left-to-right traversal of the
directed acyclic graph of base classes, where “left-to-right” is the
order of appearance of the base classes in the derived class
base-specifier-list.(13.2) — Then, direct base classes are
initialized in declaration order as they appear in the
base-specifier-list (regardless of the order of the mem-initializers).
So, since A is a virtual base class, it's initialized directly by the most derived class (D). Only afterward, the direct base classes are initialized--but for anything to compile, the most derived class must be able to initialize the virtual base class(es).
There is one point some might find interesting in a case like this. Let's modify your class structure just a tiny bit, so we to the necessary initialization, and (importantly) initialize with a unique value in each constructor:
#include <iostream>
class A {
int i;
public:
A(int i) : i(i) {}
void show() { std::cout << "value: " << i << "\n"; }
};
class B : virtual public A{
public:
B() : A(10) {}
};
class C : virtual public A {
public:
C() : A(20) {}
};
class D : public B, public C {
public:
D() : A(0) {}
};
int main() {
D d;
d.show();
}
In this case, what exactly happens? We have three different constructors each "thinking" it's going to initialize the A object with a different value? Which one "wins"?
The answer is that the one in the most-derived constructor (D::D) is the one that' used to initialize the virtual base class object, so that's the one that "wins". When we run the code above, it should print 0.

Deviation with virtual keyword

I have below structure defied as
struct A{
string s;
A() {
cout<<"in a default\n";
}
A(string t): s(t) {
cout<<"in a param \n";
}
};
struct B: virtual public A{
B(): A("B"){
cout<<"in b\n";
}
};
struct C: virtual public A {};
struct D: public B, public C {};
int main()
{
D d;
}
with A as virtual base class in both C and B,output is as follows
in a default
in b
With A as virtual base class for only B ,output is as follows
in a default
in b
in a default
with A as virtual base class for only C ,output is as follows
in a default
in a param
in b
and with no virtual base class ,output is as follows
in a param
in b
in a default
can any one explain me the deviation?
Virtual inheritance is there to resolve what's known as the "Diamond of death"
In summary, the issue is that if you called D::[some function in A], which A would it pick - the one from B, or the one from C, or that makes no sense that the separation exists?
You can read more about the issue here.
https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem

Accessing the variable of the base class from derived class in Hybrid Inheritance

I have written a C++ program.
#include <iostream>
#include <string>
using namespace std;
class A
{
int a;
public:
void read()
{
cin>>a;
}
};
class B:public A
{
public:
B()
{ }
};
class C:public A
{
public:
C()
{}
};
class D:public B,public C
{
public:
void display()
{
cout<<a<<endl;
}
};
void main()
{
A a1;B b1;C c1;
D d1;
d1.display();
}
I get a message saying there is ambiguity. B is inheriting A.. So B class would inherit item 'a' from class A. Also, C class will inherit item 'a' from class A. Now if im trying to inherit both B and C classes in class D, which item 'a' will i be able to access ?? from class B or from class C ?? Is there any way where i can remove the ambiguity .?
You can fix your ambiguity problem by using one of the following options:
Be explicit about the base class
Use B as the explicit base class
void display()
{
cout<< B::a <<endl;
}
or use C as the explicit base class.
void display()
{
cout<< C::a <<endl;
}
Use virtual inheritance
Change B and C to use virtual inheritance.
class B: virtual public A
{
public:
B() {}
};
class C: virtual public A
{
public:
C() {}
};

Why output is showing errors

This is a code fro diamond tree problem of multiple inheritance
and according to me this code is cool but it is showing some error on compilation
..help me to figure the error
#include<iostream>
using namespace std;
class A //A Diamond tree problem
{
int x;
public:
A(int i) { x = i; }
void print() { cout << x; }
};
class B: virtual public A
{
public:
B():A(10) { }
};
class C: virtual public A
{
public:
C():A(20) { }
};
class D: public B, public C{
};
int main()
{
D d;
d.print();
return 0;
}
It would be useful to see the error:
In constructor ‘D::D()’:
error: no matching function for call to ‘A::A()’
When using virtual inheritance, the virtual base class must be initialised by the most derived class. In this case, that is D; so in order to be able to instantiate D, it must initialise A:
class D: public B, public C
{
public:
D():A(42) {}
};
Alternatively, you could provide A with a default constructor. Declaring any constructor will prevent the compiler from implicitly generating one for you.
You need to provide default construct for D and call A in member initialize list:
class D: public B, public C{
public:
D():A(30){}
};
Or you could provide a default A constructor
A():x(0) {}