C++ Diamond of Death - c++

Ok so I understand how to solve the problem of the diamond of death inheritance when you have full control over all the classes but what if you only have control over the last class to inherit from both
So I have this:
class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};
and I have no way of editing B and C only D, is there an easy way I can do this?

The is a very good reason you can't force B and C to share A. Consider:
struct A {int i;};
struct B : A {
B(){i=3;}
void foo() {
//crash if i!=3
}
};
struct C : A {
C(){i=4;}
void bar() {
//crash if i!=4
}
};
B and C are good classes. They can't handle a situation that they won't get in (invalid value of i).
If there was a way to do what you ask for (struct D:B,C, where B and C share A), what will be the value of D::A::i?
virtual inheritance means "I need this class, but I won't require some valid values for it, and I completely fine with somebody else mess with it".

Fake it by containment. Have D contain B and C and give D the same public interface as the union of B and C's public interface.
Then call the appropriate methods of B and C from D's public interface.
Of course you will have a problem casting and polymorphism as it won't follow the laws of inheritance.
In short, there's no good way.

Related

Upcasting to a C++ class that is a base class in more than one way (without having to use virtual inheritance)

class A { };
class B : public A {};
class C : public A, public B {};
int main()
{
C c;
A *pA = static_cast<A *>(&c);
}
In the above code, class C is derived from class A in two different paths:
1. Directly from A
2. Indirectly through B i.e. A<-B<-C
So, when I cast an object of class C into a pointer to class A, g++ on Linux reports the following error:
error: A is an ambiguous base of C
I have also tried the same code by removing the static cast as follows:
A *pA = &c;
But, I still get exactly the same error.
Is there any solution for this? BTW, the same works fine without error on Windows using Visual C++ compiler.
I know that virtual inheritance solves this but I need a solution to make this work on g++ on Linux without having to use virtual inheritance. Rather than having to use virtual inheritance, is there any way I can instead specify one of the two path and get rid of the ambiguity. Many thanks!
If you can modify C, one possible approach would be to "inject" a dummy base class between it and A:
class A { };
class B : public A {};
class AlmostA : public A {};
class C : public AlmostA, public B {};
int main()
{
C c;
A *pA = static_cast<A*>(static_cast<AlmostA*>(&c));
}
[Live example]
You can even embed the dual static casts into a function in C.
Long story short, inherit from A virtually to avoid having two distinct As being a part of C:
class A { };
class B : virtual public A {};
class C : virtual public A, public B {};
Now your code will compile and run correctly.
Unlike "regular" base classes, virtual base classes are inherited only once, regardless of the number of paths that have them. Read this Q&A for a detailed explanation of how they work.

Check if the type comes from a given parent type

Simplifed example of my problem :
I have an abstract class A. I have two abstract classes B and C inheriting from A. And I have a lot of final classes inheriting from B or C :
class A;
class B : public A;
class C : public A;
class B1 : public B;
class B2 : public B;
class C1 : public C;
class C2 : public C;
I implement an algorithm recieving a pointer of A having to know if the type comes from B or C to work properly :
void algorithm(boost::shared_ptr<const A> a)
{
if(*a is a B instance)
// do something
else if(*a is a C instance)
// do something other
}
How can I check that simply without C++11 ?
I know how to check the final type with typeid(*a) == typeid(C1), but I don't know how to check a parent type...
You can use dynamic_pointer_cast:
if (std::dynamic_pointer_cast<B>(a)) {
...
}
else if (std::dynamic_pointer_cast<C>(a) {
...
}
Use dynamic_cast.
if (dynamic_cast<B *>(a))
{
// // a actually points at a B, or something derived unambiguously from B
}
Of course, more generally, you need to revisit the design of your function. More often than not, it would be better that it not need to know about classes derived from A. Avoiding that usually means using A as a polymorphic base that provides an interface to all functionality needed in the function (e.g. set of virtual functions that classes like B and C might specialise for themselves).

Create object that inherits from base-class

Maybe this is a bit of a beginner's question but I need some help regarding this issue.
Assume there is a class A that inherits from class B that itself inherits from class C.
Now when class A constructor looks like this everything is fine:
A::A(params)
:B(params)
{
}
Next I tried this but it fails:
A::A(params)
:C(params)
{
}
Why can't I ignore inheritance from B here - or is there a way to make this possible? Defining A as follows does not work, here compiler complains C is already a base class of A:
class A : B, C
Why can't I ignore inheritacne from B here - or is there a way to make this possible?
Because classes can only decide how to construct their direct subobject. The direct subobject for A is B and for B is C. The B object needs to be constructed too, you can't bypass it.
The error you got, basically complains about this.
Defining A as follows does not work, here compiler complains C is already a base class of A: class A : B,C
With:
class A : B, C
you are actually declaring a private multiple inheritance. And since you said B has already a subobject (inherits from) C, the compiler is complaining that inheriting from C in A is useless.
But please remember to always specify the private/protected/public kind of inheritance so that you avoid confusion. By default the inheritance for classes is private and for structs is public. So the above code corresponds to:
class A : private B, private C
You should write:
class C
{
public: C(ParamType param) { ... }
};
class B : public C
{
public: B(ParamType param) : C(param) { ... }
};
class A : public B
{
public: A(ParamType param) : B(param) { ... }
};
There is really no other way....

Share instance of base class for indirect base classes possible?

I must admit I'm having trouble formulating this question, but I'll try my best to be precise. I have tried to search for an answer to my question, but I suspect I have been unable to find what I'm looking for, as I'm not exactly sure what to call this.
I have a base class A, and several child classes inheriting from this base class. I then make another class X that inherits from some of the mentioned child classes. The problem I'm now facing is that each of the classes X inherits, have their own instance of class A. The code below should give a better understanding of what I mean.
class A;
class B : public A;
class C : public A;
class X : public B, public C;
Is there a way to make class B and C share the same instance of class A, when they are both acting as indirect base classes for the same class?
To give an example of why I want this, lets look at this code.
class A
{
int _x;
};
class B : public A
{
void outputX(){std::cout << A::_x << std::endl;
};
class C : public A
{
void setX(int x){A::_x=x;}
};
class X : public B, public C
{
C::setX(5);
// this will output an un-initialized _x,
// as B and C have their own version of A
B::outputX()
};
Now I realize this seems rather unnecessary in this example here, but in my real situation I like to think it would be a good solution if B and C shared instance of A in class X.
Is this at all possible?
You can solve this by using virtual inheritance:
class B : virtual public A;
class C : virtual public A;
class X : virtual public B, virtual public C;
See more on the diamond problem.

How can I avoid the Diamond of Death when using multiple inheritance?

http://en.wikipedia.org/wiki/Diamond_problem
I know what it means, but what steps can I take to avoid it?
A practical example:
class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};
Notice how class D inherits from both B & C. But both B & C inherit from A. That will result in 2 copies of the class A being included in the vtable.
To solve this, we need virtual inheritance. It's class A that needs to be virtually inherited. So, this will fix the issue:
class A {};
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};
virtual inheritance. That's what it's there for.
I'd stick to using multiple inheritance of interfaces only. While multiple inheritance of classes is attractive sometimes, it can also be confusing and painful if you rely on it regularly.
Inheritance is a strong, strong weapon. Use it only when you really need it. In the past, diamond inheritance was a sign that I was going to far with classification, saying that a user is an "employee" but they are also a "widget listener", but also a ...
In these cases, it's easy to hit multiple inheritance issues.
I solved them by using composition and pointers back to the owner:
Before:
class Employee : public WidgetListener, public LectureAttendee
{
public:
Employee(int x, int y)
WidgetListener(x), LectureAttendee(y)
{}
};
After:
class Employee
{
public:
Employee(int x, int y)
: listener(this, x), attendee(this, y)
{}
WidgetListener listener;
LectureAttendee attendee;
};
Yes, access rights are different, but if you can get away with such an approach, without duplicating code, it's better because it's less powerful. (You can save the power for when you have no alternative.)
class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};
In this the attributes of Class A repeated twice in Class D which makes more memory usage... So to save memory we make a virtual attribute for all inherited attributes of class A which are stored in a Vtable.
Well, the great thing about the Dreaded Diamond is that it's an error when it occurs. The best way to avoid is to figure out your inheritance structure beforehand. For instance, one project I work on has Viewers and Editors. Editors are logical subclasses of Viewers, but since all Viewers are subclasses - TextViewer, ImageViewer, etc., Editor does not derive from Viewer, thus allowing the final TextEditor, ImageEditor classes to avoid the diamond.
In cases where the diamond is not avoidable, using virtual inheritance. The biggest caveat, however, with virtual bases, is that the constructor for the virtual base must be called by the most derived class, meaning that a class that derives virtually has no control over the constructor parameters. Also, the presence of a virtual base tends to incur a performance/space penalty on casting through the chain, though I don't believe there is much of a penalty for more beyond the first.
Plus, you can always use the diamond if you are explicit about which base you want to use. Sometimes it's the only way.
I would suggest a better class design. I'm sure there are some problems that are solved best through multiple inheritance, but check to see if there is another way first.
If not, use virtual functions/interfaces.
Use inheritance by delegation. Then both classes will point to a base A, but have to implement methods that redirect to A. It has the side effect of turning protected members of A into "private" members in B,C, and D, but now you don't need virtual, and you don't have a diamond.
This is all I have in my notes about this topic. I think this would help you.
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 there is a member in A that B and C, and D does not override it, then which member does D inherit: that of B, or that of C?
struct A { int a; };
struct B : A { int b; };
struct C : A { int c; };
struct D : B, C {};
D d;
d.a = 10; //error: ambiguous request for 'a'
In the above example, both B & C inherit A, and they both have a single copy of A. However D inherits both B & C, therefore D has two copies of A, one from B and another from C. If we need to access the data member an of A through the object of D, we must specify the path from which the member will be accessed: whether it is from B or C because most compilers can’t differentiate between two copies of A in D.
There are 4 ways to avoid this ambiguity:
1- Using the scope resolution operator we can manually specify the path from which a data member will be accessed, but note that, still there are two copies (two separate subjects) of A in D, so there is still a problem.
d.B::a = 10; // OK
d.C::a = 100; // OK
d.A::a = 20; // ambiguous: which path the compiler has to take D::B::A or D::C::A to initialize A::a
2- Using static_cast we can specify which path the compiler can take to reach to data member, but note that, still there are two copies (two separate suobjects) of A in D, so there is still a problem.
static_cast<B&>(static_cast<D&>(d)).a = 10;
static_cast<C&>(static_cast<D&>(d)).a = 100;
d.A::a = 20; // ambiguous: which path the compiler has to take D::B::A or D::C::A to initialize A::a
3- Using overridden, the ambiguous class can overriden the member, but note that, still there are two copies (two separate suobjects) of A in D, so there is still a problem.
struct A { int a; };
struct B : A { int b; };
struct C : A { int c; };
struct D : B, C { int a; };
D d;
d.a = 10; // OK: D::a = 10
d.A::a = 20; // ambiguous: which path the compiler has to take D::B::A or D::C::A to initialize A::a
3- Using virtual inheritance, the problem is completely solved: If the inheritance from A to B and the inheritance from A to C are both marked "virtual", C++ takes special care to create only one A subobject,
struct A { int a; };
struct B : virtual A { int b; };
struct C : virtual A { int c; };
struct D : B, C {};
D d;
d.a = 10; // OK: D has only one copy of A - D::a = 10
d.A::a = 20; // OK: D::a = 20
Note that "both" B and C have to be virtual, otherwise if one of them is non-virtual, D would have a virtual A subobject and another non-virtual A subobject, and ambiguity will be still taken place even if class D itself is virtual. For example, class D is ambiguous in all of the following:
struct A { int a; };
struct B : A { int b; };
struct C : virtual A { int c; };
struct D : B, C {};
Or
struct A { int a; };
struct B : virtual A { int b; };
struct C : A { int c; };
struct D : B, C {};
Or
struct A { int a; };
struct B : A { int b; };
struct C : virtual A { int c; };
struct D : virtual B, C {};
Or
struct A { int a; };
struct B : virtual A { int b; };
struct C : A { int c; };
struct D : virtual B, C {};