Avoid calling base constructor 2 times - c++

Say I have several classes that inherit like so.
#include <iostream>
struct A {
A() {std::cout << "a";}
};
struct B : A {};
struct C : A {};
struct D : B, C {};
int main {
D d;
}
On executing the program, as expected, I see two A objects were constructed, one for the B and one for the C object that are constructed when creating a D object. Whoever, how can I not create two A objects? I want the same A object to be used to create B and C objects. Is this possible?

If B and C both use virtual inheritance for A, then there will only be a single base class object for each D object:
struct B : virtual A {};
struct C : virtual A {};
//...
D d; //prints "a" rather than "aa"
Live demo

If you're looking for a non-polymorphic solution, you're out of luck. Otherwise, change to the following:
struct B : virtual A {};
struct C : virtual A {};

As written, every D object has two sub-objects of type A, one inherited from class B and one inherited from class C. So the constructor of A must run twice, once for each sub-object.
If the original design is wrong, and there should only be one A sub-object, despite the use of two bases B and C, the change is to make A a virtual base of B and a virtual base of C. That way there will only be one A sub-object in a D object, and the constructor of A will only run once when a D object is constructed.

Related

What is a base class subobject?

I got that subobjects are member subobjects, base class subobjects and arrays.
I couldn't find anything that explicit explain the two first terms. In the following code for example:
struct A{int a;};
struct B{int b;};
struct C:public A,public B{};
I think that: int a is a member subobject of a possible, not yet instantiated, object of type A; int a is a base class subobject of a possible, not yet instantiated, object of type C. Is it Right? What is the definition of member subobject and base class subobject? Could you provide examples?
Whenever a class inherits from another one it inherits, too, an instance of that class:
class A { };
class B : A { };
Then class B internally looks like:
class B
{
A a; // <- implicit base class sub-object, not visible to you
};
Note that in some cases there might be even be more than one A!
class A { };
class B : A { };
class C : A { };
class D : C, B { };
D then internally looks like:
class D
{
B b; // { A a; }
C c; // { A a; }
};
with b and c being the base class sub-objects; or in a flattened representation:
class D
{
A aFromB; // inherited from B, but not a sub-object of D itself
// other members of B
A aFromC; // inherited from C, again not a sub-object of D
// other members of C
};
B and C base class sub-objects are not visible in this representation, still they are there in form of the respective A instance combined with the respective other members (think of having braces around).
If you want to avoid duplicates of A, you need to inherit virtually: class B : virtual A { } – all virtually inherited (directly or indirectly) instances of A are then combined into one single instance (though if there are non-virtually inherited ones these remain in parallel to the combined one), consider:
class A { };
class B : A { };
class C : virtual A { };
class D : virtual A { };
class E : A, B, C
{
A combinedAFromCAndD;
// other members of B
// other members of C
A separateAFromD
// other members of D
};
Note: These layouts above are just examples, concrete layouts might vary.
In your code, the base class subobjects of instances of C are the instances of A and B contained inside it. Each of those subobjects has a subobject itself (a and b); those are not considered subobjects of the instance of C (because they're subobjects of subobjects), but are considered "nested objects" of the instance of C.

Acessing to a base subobject and virtual specifier c++ [duplicate]

This question already has answers here:
In C++, what is a virtual base class?
(11 answers)
Closed 8 years ago.
I'm trying to understand what exactly purpose of a virtual specifier in base class. As said in the c++14 working draft we have:
For each distinct base class that is specified virtual, the most
derived object shall contain a single base class subobject of that
type.
From this quote I'm assume that if we create an instance c of class C which is a derived class for A and B we're create an objects of A and B implicitly.
Question: How can I access to an instances of a base classes via an instance of derived class?
An object of class struct C : A, B {}; contains two base subobjects, one of type A and one of type B. You can access them "directly":
void foo(A &);
void bar(B &);
C c;
foo(c); // accesses the A-subobject
bar(c); // accesses the B-subobject
You can also say static_cast<A&>(c) and static_cast<B&>(c) explicitly, though this is not often needed. You sometimes need to disambiguate names, though:
struct A { void f(); };
struct B { void f(); };
struct C : A, B { void f(); };
C c;
c.f(); // calls the member "f" of C
c.A::f(); // calls the member "f" of the A-base subobject of c
c.B::f(); // calls the member "f" of the B-base subobject of c
All this is not really related to the concept of virtual inheritance, which says that there is only relevant base subobject, even if it is referred to through multiple distinct inheritances:
struct V {};
struct A : virtual V {};
struct B : virtual V {};
struct C : A, B {};
In this last example, an object C c has only one base subobject of type V, not two, and the V-base subobjects of the A- and B-base subobjects of c see the same V base subobject. The virtual base is "shared" across the inheritance hierarchy.
virtual specifier is not related to accessing base sub-object, rather number of base sub-object in derived object. You can access base sub-object even if the base is not virtual. virtual is here to solve other problems like diamond inheritance problem

C++ inheritance: determine inherited methods at runtime

I have a class D that extends B which extends A. I now want to add a class C that has exactly the same interface as B but provides a different implementation. So I design it as the following:
This is not exactly what I want, as I only need an instance of D to either extend B or C and not both, however, this is only determined at runtime. The problem with the design above is of course that if I call a method in D which is implemented both in B and C, its ambiguous.
So what I would like to have is to create an instance of either B or C at runtime and then cast it into D. Every time an instance of D calls an inherited method it should use the one of its original object.
Do I need to fiddle with typeid and if/else around each method call or is there a more elegant way to do this?
class A{
virtual f1();
virtual f2();
}
class B : public virtual A{
f1();
f2();
f3();
}
class C : public virtual A{
f1();
f2();
f3();
}
class D : public B, public C{
f4(){f1(); f3)};
}
...
D* d = new D();
E* e = new E(d);
e->d->f1();
e->d->f4();
Instances of D are then passed to another class (E) which does stuff with D and therefore, I cannot modify the interface of D.
I think you're having inheritance the wrong way around, what you do is define all the methods that you want to call on what you call class D as virtual methods in class A, class B and C both have their own implementation of those methods.
Then you use a data structure of type A*, fill that with pointers to objects of type B and C and you call the methods that you need to call on all the objects in the data structure that contains pointers of type A*, the vtable mechanism will then make sure that the implementation of class B or C is used depending on what the actual object's type is.
See What is the difference between a concrete class and an abstract class?
It sounds like you just want
class A{
virtual void DoMagic() = 0;
};
class B{
virtual void DoMagic(){};
};
class D{
virtual void DoMagic(){};
};
...
bool INeedB = true;//or false
A* a;
if(INeedB){
a= new B();
}else{
a = new C();
}
a->DoMagic(); // will call the appropriate method based on the value of INeedB;
Unless D actually has behavior of its own? Then you can look at decorator pattern, and make D the decorator of an instance of B or C.
Edit: Your D class doesnt need to inherit any of A B or C at all.
class D{
D(A* aObj):a(aObj){}
void f3(){ a->f1();a->f2();}
A *a;
};
Replace A *a in above example with D d
C++ is a statically-typed language. Whatever you do with type declaration is elaborated at compile time, hence the inheritance graph of D cannot be defied at runtime.
What you probably need is to have A as a polymorphic base (with all relevant method virtual, included the destructor) for both B and C (concrete implementation of that), and D an "owner of an A", by containing an A* thet will be assigned at D construction to a new B or new C depending on input.
D destructor will call delete A, and now you have to decide about copy and assignment.
My suggestion is not to use an A*, but a std::unique_ptr (will make the owned object movable between D-s) or std::shared_ptr.
In case you need each D to have its own A, then let A to have a clone method (overridden in B and C, to return a new B and new C respectively) and call it in D's copy ctor and assign operator.
It seems like D doesn't need to inherit from A (or B or C) at all. Instead it just needs to call function in either an instance of B or an instance of C.
You can implement it something like this:
class A
{
public:
virtual void f1();
virtual void f2();
};
class B : public A;
class C : public A;
class D
{
A* b_or_c;
public:
D(A* a_pointer)
: b_or_c(a_pointer)
{}
void f3()
{
b_or_c->f1();
b_or_c->f2();
}
};
Can be used like this:
B b; // An instance of B
C c; // An instance of C
D d1(&b);
D d2(&c);
d1.f3(); // Will cause `f1` and `f2` in the object `b` to be called
d2.f3(); // Will cause `f1` and `f2` in the object `c` to be called

Understanding virtual base classes and constructor calls

I'm a bit confused about how virtual base classes work. In particular, I was wondering how the constructor of the base class gets called. I wrote an example to understand it:
#include <cstdio>
#include <string>
using std::string;
struct A{
string s;
A() {}
A(string t): s(t) {}
};
struct B: virtual public A{
B(): A("B"){}
};
struct C: virtual public A {};
struct D: public B, public C {};
struct E: public C, public B {};
struct F: public B {};
int main(){
D d;
printf("\"%s\"\n",d.s.c_str());
E e;
printf("\"%s\"\n",e.s.c_str());
F f;
printf("\"%s\"\n",f.s.c_str());
B b;
printf("\"%s\"\n",b.s.c_str());
}
Which outputs
""
""
""
"B"
I wasn't sure what would happen in the first two cases, but for the third one at least I was expecting the output to be "B". So now I'm just confused. What are the rules for understanding how the constructor of A gets called?
There is always just one constructor call, and always of the actual, concrete class that you instantiate. It is your responsibility to endow each derived class with a constructor which calls the base classes' constructors if and as necessary, as you did in B's constructor.
Update: Sorry for missing your main point! Thanks to ildjarn.
However, your B inherits virtually from A. According to the standard (10.1.4 in the FIDS), "for each distinct baseclass that is specified virtual, the most derived object shall contain a single base class subobject of that type". In your case this means that when constructing the base, your class F immediately calls A's default constructor, not B's.
Virtual base classes are always constructed by the most derived class.

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 {};