virtual derivation & conversion ambiguous - c++

I'm learning now the different situations of ambiguity in the virtual derivation on C++.
But I have an error of Ambiguity in my code and I don't understand it's reason...
Here's my Code :
class V {
public:
int v ;
};
class A {
public:
int a ;
};
class B : public A, public virtual V {
};
class C : public A, public virtual V {
};
class D : public B, public C {
public:
void f() ;
};
void g() {
D d ;
B* pb = &d ; // No Problem
A* pa = &d ; // Error: 'A' is ambiguous base of 'D'
V* pv = &d ; // No Problem
}
I don't understand why do I have this error however I don't have errors for the other affectations.
Thank you :-)

This is completely expected in cases of multiple inheritance. What we have here is a case of Diamond inheritance. D now has two copies of A, one inherited from B, and one inherited from C. You need to specify which of B or C the members of A exposed to D come from.
See: Using C++, how do I correctly inherit from the same base class twice?
You might consider:
Using virtual inheritance:
class B : public virtual A, public virtual V {...};
class C : public virtual A, public virtual V {...};
Using composition as a way out of multiple inheritance.
I suggest reading Solving the Diamond Problem with Virtual Inheritance

Related

Is this example working with virtual inheritance in C++?

Could I do this?
class A {
public:
virtual void aFoo() = 0;
};
class B : virtual public A {
public:
virtual void aFoo() { ... }
};
class D : public A {};
class C : public B, virtual public D {};
The issue is with the implementation of aFoo() in B and the lack of it in C. When it comes to compiling I see this error:
error: no unique final overrider for ‘virtual void A::aFoo()’ in ‘C’
Shouldn't it be possible to override a pure virtual method of a virtual base class in B?
Just edited the example to match the actual use case. Now looking at it in this simplified way I am not quite sure if this is even possible, let alone good design.
You need virtual inheritance in this way:
struct A {
virtual int f() = 0;
};
struct B : virtual A {
int f() { return 1; }
};
struct C : virtual A {};
struct D : B, C {};
int main() {
D d;
return d.f();
}
In the dupe I commented you can see this relation
A
/ \
B C
\ /
D
for virtual inheritance and
A A
| |
B C
\ /
D
without virtual inheritance.
In the second case D contains two function definitions. One is implemented and one isn't.

C++: multiple inheritance using virtual

Still learning basics of C++
I have a very simple query regarding the virtual keyword in multiple inheritance.
I have the following code:
class A {};
class B : public A {};
//1. class C : public A, public B {};
//2. class C : virtual public A, public B {};
//3. class C : public A, virtual public B {};
//4. class C : virtual public A, virtual public B {};
int main() {
C f;
return 0;
}
Now I know (by actually trying this code out), that 1 and 3, both cases where we do not use virtual keyword while inheriting class A work.
I understand it is the Diamond Problem of multiple inheritance, and the compiler error goes away when I inherit class A as virtual in class B:
class B: virtual public A
But I wanted to experiment with the code and removed it.
My question is, Why does creation of an object of class C fail when we inherit class A using virtual?
Note: I could not find a good article to explain in depth what this virtual keyword means and how the compiler reads it and what does the compiler do after reading the Virtual Keyword.
EDIT:
This is an experiment that I am doing, so no practical use (to me personally).
When do this:
class A {};
class B : public A {};
class C : virtual public A, virtual public B {};
int main() {
C f;
return 0;
}
Compiler throws error: error C2584: 'C': direct base 'A' is inaccessible; already a base of 'B'
even when I don't use virtual, compiler still gives the error msg as a "Warning"

Upcasting not to real base class

I'm a bit stuck with such awful problem of bad class hierarchy.
class A {...}; // abstract
class B : public A {...}; // abstract
class C {...}; // abstract
class a1 : public B, public C {...}; // indirect inheritance of A
class c1 : public A, public C {...};
The question: is it possible convert a pointer(reference) to C into pointer(reference) to class A.
I understand that best solution is to make just class C inherited from A, but still it can cause some problems with class a1 (two base A).
The question: is it possible convert a pointer(reference) to C into pointer(reference) to class A.
Not unless the classes are polymorphic i.e. have at least one virtual member function. In that case dynamic_cast can be used to side cast, as shown in StoryTeller's answer.
However, if that C pointer(reference) points to a child that inherits A, then you can first cast down to that child pointer, and then to A.
c1 c;
C& cref = c;
A& aref = static_cast<c1&>(cref);
That's of course not necessarily ideal because you cannot convert just any arbitrary C pointer whose concrete type is unknown.
I understand that best solution is to make just class C inherited from A
If you did this, then all C pointers would be implicitly convertible to A pointers.
but still it can cause some problems with class a1 (two base A).
To work around the problems, you need shared bases i.e virtual inheritance.
struct A {}; // abstract
struct B : virtual A {}; // abstract
struct C : virtual A {}; // abstract
struct a1 : B, C {}; // indirect inheritance of A
struct c1 : C {};
int main() {
c1 c;
C& cref = c;
A& aref = cref;
}
What you are trying to do is called a "side-cast". And the built-in dynamic_cast expression can do that. But it isn't cheap, and you better not have turned off support for RTTI in your project (you already mentioned your classes are abstract, so that entails virtual functions, whose declarations are needed for RTTI to be generated along).
See it Live
#include <cassert>
struct A {
virtual ~A() = default;
};
struct B : public A {
virtual ~B() = default;
};
struct C {
virtual ~C() = default;
};
struct a1 : public B, public C {
a1() = default;
virtual ~a1() = default;
}; // indirect inheritance of A
int main() {
a1 a;
C* c = &a;
assert(dynamic_cast<A*>(c) != nullptr);
return 0;
}
But your sentiments about needing to re-design your classes are in my opinion highly warranted. The need to do a side cast should not arise.
Both answers above are correct, but the first one is more widely explained, I think.
Another solution that I will possibly use is creating a weird visitor, like:
PointerCreator
{
void visit ( const a1 & _a )
{
m_pointerToA = &_a;
}
void visit ( const c1 & _c )
{
m_pointerToA = &_a;
}
A * m_pointerToA;
};
PointerCreator pC;
a1.accept( pC );
A& = *pC.m_pointerToA;

C++ pseudo-diamond [duplicate]

Given the following code (without virtual inheritance) :
class A
{
public:
virtual void f() = 0;
};
class B : public A
{
public:
virtual void f() {}
};
class C : public A
{
public:
virtual void f() {}
};
class D : public B, public C
{
/* some code */
};
int main()
{
D d;
return 0;
}
the code compile.
On the other hand , here :
class A
{
public:
virtual void f() = 0;
};
class B : virtual public A
{
virtual void f() {}
};
class C : virtual public A
{
virtual void f() {}
};
class D : public B, public C
{
/* some code */
};
int main()
{
D d;
return 0;
}
The compiler presents a compilation error:
no unique final overrider for 'virtual void A::f()' in 'D' .
Why is it different in the second code ?
Your first scenario hierarchy corresponds to:
F() F()
A A
| |
F() B C F()
\ /
D
Where D is not abstract, because there are two A subobjects in an object of type D: One that is made concrete by B through the lattice of B, and another that is made concrete through the lattice of C.
Unless you try to invoke the function F() on object of D there will not be any ambiguity.
Your second scenario hierarchy corresponds to:
F()
A
/ \
F() B C F()
\ /
D
In this scenario, the object D has a single Base class A sub object, and it must override and provide implementation of the pure virtual function in that subobject.
Herb Sutter's articles in Guru Of The Week(GOTW) are a nice read for Multiple Inheritance:
Multiple Inheritance Part I
Multiple Inheritance Part II
Multiple Inheritance Part III
With the virtual inheritance a D object has a single base-class A sub-object. This single sub-object can’t have two different implementations of a virtual function. In contrast, without virtual inheritance a D object has two distinct base-class A sub-objects, each with its own implementation of the function (which is OK until you try to call it on a D object, at which point you need to indicate which one you want).
Cheers & hth.

Virtual Base Class in C++

I have a query regarding the virtual base class. In order to resolve the "dreaded diamond of death" /ambiguity problem in multiple inheritance, virtual base class is introduced.
class A { public: void Foo() {} };
class B : public virtual A {};
class C : public virtual A {};
class D : public B, public C {};
What will happen when a keyword virtual is not used in class C declaration. Could you please explain me in detail?
class A { public: void Foo() {} };
class B : public virtual A {};
class C : public A {};
class D : public B, public C {};
If your inheritance is not virtual then A members will be present twice in D class.
If A had a field named _a, then, in D, writing B::_a or C::_a would refer to two different memory zones. If your inheritance is virtual then you have only one memory zone.
If you are using virtual than there will be no ambiguity when you call foo() using the instance of Class D. and if you are not using virtual than it will be ambiguity..
But be careful that virtual inheritance cost more so use it carefully..
class A { public: void Foo() {} };
class B : public virtual A {};
class C : public A {};
class D : public B, public C {};
If the inheritance from the A class to B marked virtual but not A class to C, then C++ will create a single virtual A (D inherits B, B inherits A) and a nonvirtual A (D inherits C, C inherits A). Therefore, your code will not solve the diamond problem:
D d_object;
A &a_ref = d_object; // error raised -> B::A or C::A