c++ - Why is call to nested inherited abstract constructor required? [duplicate] - c++

The following code won't compile:
class A {
public:
A(int) {}
};
class B: virtual public A {
public:
B(): A(0) {}
};
// most derived class
class C: public B {
public:
C() {} // wrong!!!
};
If I call A's constructor in C's constructor initialization list, that is:
// most derived class
class C: public B {
public:
C(): A(0) {} // OK!!!
};
it does work.
Apparently, the reason is because virtual base classes must always be constructed by the most derived classes.
I don't understand the reason behind this limitation.

Because it avoids this:
class A {
public:
A(int) {}
};
class B0: virtual public A {
public:
B0(): A(0) {}
};
class B1: virtual public A {
public:
B1(): A(1) {}
};
class C: public B0, public B1 {
public:
C() {} // How is A constructed? A(0) from B0 or A(1) from B1?
};

Because in the class hierarchy having a virtually inherited base class, the base class would/may be shared by multiple classes (in diamond inheritance for example, where the same base class is inherited by multiple classes). It means, there would be only one copy of the virtually-inherited base class. It essentially means, the base class must be constructed first. It eventually means the derived class must instantiate the given base class.
For example:
class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2 // A is shared, and would have one copy only.

I find this rule error-prone and cumbersome (but then, what part of multiple inheritance isn't?).
But the logically imposed order of construction must differ from the case of normal (non-virtual) inheritance. Consider Ajay's example, minus virtual:
class A;
class B1 : A;
class B2 : A;
class C: B1,B2
In this case for each C two As are constructed, one as part of B1, the other one as part of B2. The code of the B classes is responsible for that, and can do it. The order of events is:
Start C ctor
Start B1 ctor
A ctor (in B's ctor code)
End B1 ctor
Start B2 ctor
A ctor (in B's ctor code)
End B2 ctor
End C ctor
Now consider virtual inheritance in
class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2
One order of event is
Start C ctor
A ctor // not B's code!
Start B1 ctor
// NO A ctor
End B1 ctor
Start B2 ctor
// NO A ctor
End B2 ctor
End C ctor
The important logical distinction is that the virtually inherited base class sub-object of type A is part of the most derived class and under the control of it (here C).
B's constructors know nothing about and cannot access A. Consequently they cannot construct sub-objects of A, including base classes.

Related

C++ Correct design to iterate over members of derived instances

I have a base class that holds a vector of pointers to derived classes and a virtual recursive method like this:
class Base
{
std::vector<Base*> vec;
public:
Base(std::vector<Base*> vec = {}) : vec {vec} {}
virtual ~Base() = default;
virtual void f() const
{
if (vec.size() == 0)
throw std::logic_error("Last children should implement f()")
for (auto * part : vec)
part->f();
}
}
The method f() is recursive and the last child of Base should override it. For example the following works
Where the first derived class is
class B : public Base
{
B() : Base() {}
virtual void f() const
{
std::cout << "In B\n";
}
}
class A : public Base
{
B b_,c_;
public:
A(B b, B c) : Base({&b_,&c_}), b_ {b}, c_{c} {}
}
If I call
B b,c;
A a(b,c);
a.f()
It will print twice "In B"correctly. Notice that A does not override f() so Base::f() is called, this loops and calls B::f() twice, once for b and once for c. However if I go one nested class more, for example by having
class C : public Base
{
A a_;
B b_;
public:
C(A a, B b): Base({&a_, &b_}), a_{a}, b_{b} {}
}
And I call C::f() the program segfaults. I suppose this is because there are some temporaries and their destructors delete the pointers held by Base. Is the solution to this to hold shared_ptr? or is there a better design? I cannot hold unique_ptr cause that would make all derived classes not copyable.
public C(A a, B b): Base({&a, &b}), a{a}, b{b} {}
Firstly, you can't have public there.
Your base points to the parameters of the constructor. Those parameters are destroyed when the constructor finishes and the pointers become invalid. Point to the members instead:
C(A a, B b): Base({&this->a, &this->b}), a{a}, b{b} {}
Note however that the implicit copy and move constructors and assignment operators of the class are broken because they will make the copied object point to the members of the copy source, rather than the members of the copy itself. So, you'll need implement those as well.
is there a better design?
Possibly a better approach: Instead of storing the pointers in the base sub object, write a virtual function that derived classes can override, and which returns a range of pointers to children.

Why must virtual base classes be constructed by the most derived class?

The following code won't compile:
class A {
public:
A(int) {}
};
class B: virtual public A {
public:
B(): A(0) {}
};
// most derived class
class C: public B {
public:
C() {} // wrong!!!
};
If I call A's constructor in C's constructor initialization list, that is:
// most derived class
class C: public B {
public:
C(): A(0) {} // OK!!!
};
it does work.
Apparently, the reason is because virtual base classes must always be constructed by the most derived classes.
I don't understand the reason behind this limitation.
Because it avoids this:
class A {
public:
A(int) {}
};
class B0: virtual public A {
public:
B0(): A(0) {}
};
class B1: virtual public A {
public:
B1(): A(1) {}
};
class C: public B0, public B1 {
public:
C() {} // How is A constructed? A(0) from B0 or A(1) from B1?
};
Because in the class hierarchy having a virtually inherited base class, the base class would/may be shared by multiple classes (in diamond inheritance for example, where the same base class is inherited by multiple classes). It means, there would be only one copy of the virtually-inherited base class. It essentially means, the base class must be constructed first. It eventually means the derived class must instantiate the given base class.
For example:
class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2 // A is shared, and would have one copy only.
I find this rule error-prone and cumbersome (but then, what part of multiple inheritance isn't?).
But the logically imposed order of construction must differ from the case of normal (non-virtual) inheritance. Consider Ajay's example, minus virtual:
class A;
class B1 : A;
class B2 : A;
class C: B1,B2
In this case for each C two As are constructed, one as part of B1, the other one as part of B2. The code of the B classes is responsible for that, and can do it. The order of events is:
Start C ctor
Start B1 ctor
A ctor (in B's ctor code)
End B1 ctor
Start B2 ctor
A ctor (in B's ctor code)
End B2 ctor
End C ctor
Now consider virtual inheritance in
class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2
One order of event is
Start C ctor
A ctor // not B's code!
Start B1 ctor
// NO A ctor
End B1 ctor
Start B2 ctor
// NO A ctor
End B2 ctor
End C ctor
The important logical distinction is that the virtually inherited base class sub-object of type A is part of the most derived class and under the control of it (here C).
B's constructors know nothing about and cannot access A. Consequently they cannot construct sub-objects of A, including base classes.

How to call copy constructor of all base classes for copying most derived class object in diamond inheritance in C++?

Consider the below code:
#include<iostream>
using namespace std;
class A
{
public:
A() {cout << "1";}
A(const A &obj) {cout << "2";}
};
class B: virtual A
{
public:
B() {cout << "3";}
B(const B & obj) {cout<< "4";}
};
class C: virtual A
{
public:
C() {cout << "5";}
C(const C & obj) {cout << "6";}
};
class D:B,C
{
public:
D() {cout << "7";}
D(const D & obj) {cout << "8";}
};
int main()
{
D d1;
cout << "\n";
D d(d1);
}
The output of the program is below:
1357
1358
So, for line D d(d1) the copy constructor of D class is bein called. During inheritance we need to explicitly call copy constructor of base class otherwise only default constructor of base class is called. I understood till here.
My Problem:
Now I want to call copy constructor of all base classes during D d(d1) execution. For that if I try below
D(const D & obj) : A(obj), B(obj), C(obj) {cout << "8";}
Then I get this error:
error: 'class A A::A' is inaccessible within this context
How to resolve the issue. I want copy constructor of A, B and C when copy constructor of D gets called. It might be very small change but I am not getting.
First, lets change your inheritance as currently it is private:
class B : virtual protected A {...};
class C : virtual protected A {...};
Now, in your copy constructor, explicitly specify that the copy constructors of A and B and C should be called:
class D : protected B, protected C {
D(const D & obj) : A(obj), B(obj), C(obj) {cout << "8";}
};
And the output will be as desired (2468).
Why?
When we have virtual base classes, they must be initialized by the most derived class, otherwise there would be ambiguity concerning whether B or C for example is responsible for the construction of A.
§12.6.2, (13.1):
In a non-delegating constructor, initialization proceeds in the following order:
First, and only for the constructor of the most derived class (1.8),
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.
In particular, if you define a copy constructor, and omit the list of copy constructors it should call, then the default constructors will be used.
The way you have inherited your classes, all of them use private inheritance.
By changing the inheritance of B from A and C from A to be protected or public, you can resolve the problem.
class B : protected virtual A
{
...
}
class C : protected virtual A
{
...
}
or
class B : public virtual A
{
...
}
class C : public virtual A
{
...
}
and then update D's copy constructor to:
D(const D & obj) : A(obj), B(obj), C(obj) {cout <<"8";}
PS It's baffling to me that the default constructor works even with private inheritance.
Alternative solution which doesn't require changing the inheritance modifiers of class B or C:
class A
{
public:
A() {cout << "1";}
A(const A &obj) {cout << "2";}
};
class B: virtual A
{
public:
B() {cout << "3";}
B(const B & obj) {cout<< "4";}
};
class C: virtual A
{
public:
C() {cout << "5";}
C(const C & obj) {cout << "6";}
};
class D:B,C,virtual A
{
public:
D() {cout << "7";}
D(const D & obj) : A(obj), B(obj), C(obj) {cout << "8";}
};
Regarding access checking for constructors: from [class.access]/6
All access controls in Clause [class.access] affect the ability to
access a class member name from the declaration of a particular entity
... [ Note : This access also applies to implicit references to
constructors, conversion functions, and destructors. — end note]
similarly, [class.access]/4
Special member functions obey the usual access rules. [ Example:
Declaring a constructor protected ensures that only derived classes
and friends can create objects using it. — end example ]
Regarding base class subobject initialization: from [class.base.init]/9
In a non-delegating constructor, if a given potentially constructed
subobject is not designated by a mem-initializer-id (including the
case where there is no mem-initializer-list because the constructor
has no ctor-initializer), then ... otherwise, the entity is
default-initialized
The lack of any ctor-initializer for a base class subobject means that the subobject is default-initialized; from [dcl.init]/7
To default-initialize an object of type T means: ...
The constructor thus selected is called, with an empty argument list,
to initialize the object.
So the lack of any base in a ctor-initializer is a request for default-initialization for that base, which means calling the default constructor.
The lack of mention of a base class makes no difference; in any case, a constructor has no name and is not named in the ctor-initializer, it is referenced either explicitly or implicitly. There is nothing in the standard suggesting that access control should not be performed in such case.
It seems like the constructor, being from an inaccessible base class, cannot be called either way, so your program should not compile.
In any case, you can change the inheritance from private to protected, even add a path to the virtual base class:
class D: B, C, virtual A
{
This way, the virtual base class A is still private, but is accessible to D.

virtual inheritance constructor order

I am trying to understand better the concept of virtual inheritance, and what are its perils.
I read in another post (Why is Default constructor called in virtual inheritance?) that it (= virtual inheritance) changes the order of constructor call (the "grandmother" is called first, while without virtual inheritance it doesn't).
So I tried the following to see that I got the idea (VS2013):
#define tracefunc printf(__FUNCTION__); printf("\r\n")
struct A
{
A(){ tracefunc; }
};
struct B1 : public A
{
B1(){ tracefunc; };
};
struct B2 : virtual public A
{
B2() { tracefunc; };
};
struct C1 : public B1
{
C1() { tracefunc; };
};
struct C2 : virtual public B2
{
C2() { tracefunc; };
};
int _tmain(int argc, _TCHAR* argv[])
{
A* pa1 = new C1();
A* pa2 = new C2();
}
The output is:
A::A
B1::B1
C1::C1
A::A
B2::B2
C2::C2
Which is not what I expected (I expected the order of the 2 classes will be different).
What am I missing? Can someone explain or direct me to a source that explains it better?
Thanks!
In your example, your output is to be expected. Virtual inheritance comes into play in the instance when you have a class with multiple inheritance who's parent classes also inherit from the same class/type (i.e. the "diamond problem"). In your example, your classes might be set up to virtually inherit (if needed elsewhere in the code), but they don't necessarily 'virtually inherit' based on your example since none of the derived classes (B1/B2/C1/C2) do more than inherit directly from A.
To expand, I've tweaked your example to explain a little more:
#include <cstdio>
#define tracefunc printf(__FUNCTION__); printf("\r\n")
struct A
{
A() { tracefunc; }
virtual void write() { tracefunc; }
virtual void read() { tracefunc; }
};
struct B1 : public A
{
B1() { tracefunc; };
void read(){ tracefunc; }
};
struct C1 : public A
{
C1() { tracefunc; };
void write(){ tracefunc; }
};
struct B2 : virtual public A
{
B2() { tracefunc; };
void read(){ tracefunc; }
};
struct C2 : virtual public A
{
C2() { tracefunc; };
void write(){ tracefunc; }
};
// Z1 inherits from B1 and C1, both of which inherit from A; when a call is made to any
// of the base function (i.e. A::read or A::write) from the derived class, the call is
// ambiguous since B1 and C1 both have a 'copy' (i.e. vtable) for the A parent class.
struct Z1 : public B1, public C1
{
Z1() { tracefunc; }
};
// Z2 inherits from B2 and C2, both of which inherit from A virtually; note that Z2 doesn't
// need to inherit virtually from B2 or C2. Since B2 and C2 both virtual inherit from A, when
// they are constructed, only 1 copy of the base A class is made and the vtable pointer info
// is "shared" between the 2 base objects (B2 and C2), and the calls are no longer ambiguous
struct Z2 : public B2, public C2
{
Z2() { tracefunc; }
};
int _tmain(int argc, _TCHAR* argv[])
{
// gets 2 "copies" of the 'A' base since 'B1' and 'C1' don't virtually inherit from 'A'
Z1 z1;
// gets only 1 "copy" of 'A' base since 'B2' and 'C2' virtualy inherit from 'A' and thus "share" the vtable pointer to the 'A' base
Z2 z2;
z1.write(); // ambiguous call to write (which one is it .. B1::write() (since B1 inherits from A) or A::write() ?)
z1.read(); // ambiguous call to read (which one is it .. C1::read() (since C1 inherits from A) or A::read() ?)
z2.write(); // not ambiguous: z2.write() calls C2::write() since it's "virtually mapped" to/from A::write()
z2.read(); // not ambiguous: z2.read() calls B2::read() since it's "virtually mapped" to/from A::read()
return 0;
}
While it might be "obvious" to us humans which call we intend to make in the case of the z1 variable, since B1 doesn't have a write method, I would "expect" the compiler to choose the C1::write method, but due to how the memory mapping of objects work, it presents a problem since the base copy of A in the C1 object might have different information (pointers/references/handles) than the copy of the A base in the B1 object (since there's technically 2 copies of the A base); thus a call to B1::read() { this->write(); } could give unexpected behaviour (though not undefined).
The virtual keyword on a base class specifier makes it explicit that other classes that virtually inherit from the same base type, shall only get 1 copy of the base type.
Note that the above code should fail to compile with compiler errors explaining the ambiguous calls for the z1 object. If you comment out the z1.write(); and z1.read(); lines the output (for me at least) is the following:
A::A
B1::B1
A::A
C1::C1
Z1::Z1
A::A
B2::B2
C2::C2
Z2::Z2
C2::write
B2::read
Note the 2 calls to the A ctor (A::A) before Z1 is constructed, while Z2 only has 1 call to the A constructor.
I recommend reading the following on virtual inheritance as it goes more in depth on some of the other pitfalls to take note of (like the fact that virtually inherited classes need to use the initialization list to make base class ctor calls, or that you should avoid using C-style casts when doing such a type of inheritance).
It also explains a little more to what you were initially alluding to with the constructor/destructor ordering, and more specifically how the ordering is done when using multiple virtual inheritance.
Hope that can help clear things up a bit.
The output of compiler is right. In fact, this is about the goal of virtual inheritance. Virtual inheritance is aimed to solve the 'Diamond problem' in the multiple inheritance. For example, B inherits from A, C inherits from A and D inherits from B, C. The diagram is like this:
A
| |
B C
| |
D
So, D has two instances A from B and C. If A has virtual functions, there is a problem.
For example:
struct A
{
virtual void foo(){__builtin_printf("A");}
virtual void bar(){}
};
struct B : A
{
virtual void foo(){__builtin_printf("B");}
};
struct C : A
{
virtual void bar(){}
};
struct D : B, C
{
};
int main()
{
D d;
d.foo(); // Error
}
If I use my xlC compiler to compile and run:
xlC -+ a.C
The error message is like that:
a.C:25:7: error: member 'foo' found in multiple base classes of different types
d.foo(); // Error
^
a.C:9:18: note: member found by ambiguous name lookup
virtual void foo(){__builtin_printf("B");}
^
a.C:3:18: note: member found by ambiguous name lookup
virtual void foo(){__builtin_printf("A");}
^
1 error generated.
Error while processing a.C.
The error message is very clear, member 'foo' found in multiple base classes of different types. If we add virtual inheritance, the problem is solved. Because the construction rights of A is handled by D, there is one instance of A.
Back to your code, the inheritance diagram is like this:
A A
| |
B1 B2
| |
C1 C2
There is no 'diamond problem', this is only single inheritance. So, the construction order is also A->B2->C2, there is no difference of output.
You won't be able to see any difference in the output because the output will be same in any of the following class hiearchies:
Hiearchy 1
class A {};
class B2 : virtual public A {};
class C2 : virtual public B2 {};
Hiearchy 2
class A {};
class B2 : public A {};
class C2 : virtual public B2 {};
Hiearchy 3
class A {};
class B2 : virtual public A {};
class C2 : public B2 {};
Hiearchy 3
class A {};
class B2 : public A {};
class C2 : public B2 {};
In all these case, A::A() will be executed first, followed by B2::B2(), and then C2::C2().
The difference between them is when does A::A() get called. Does it get called from B2::B2(), or C2::C2()?
I am not 100% clear on the answer for Hiearchy 1. I think B2::B2() should get called from C2::C2 since B2 is a virtual base class of C. A::A() should get called from B2:B2() since A is a virtual base class of B2. But I could be wrong on the exact order.
In Hierarchy 2, A::A() will be called from B2::B2(). Since B2 is the virtual base class of C2, B2::B2() gets called from C2::C2(). Since A is a normal base class of B2, A::A() gets called from B2::B2().
In Hierarchy 2, A::A() will be called from C2::C2(). Since A is a virtual base class, A::A() gets called from C2::C2(). B2::B2() gets called after the call to A::A() is completed.
In Hierarchy 4, A::A() will be called from B2::B2(). I think this case needs no explanation.
To clarify my doubt regarding Hiearchy 1, I used the following program:
#include <iostream>
class A
{
public:
A(char const *from) { std::cout << "Called from : " << from << std::endl; }
};
class B2 : virtual public A
{
public:
B2() : A("B2::B2()") {}
};
class C2 : virtual public B2
{
public:
C2() : A("C2::C2()") {}
};
int main()
{
C2 c;
}
I got the following output:
Called from : C2::C2()
This confirms what #T.C indicated in his comment, which is different from what I had expected. A::A() gets called from C2::C2, not from B2::B2.

Diamond sub-problem: non-multiple inheritance in side branch still require class constructor

Strange problem occurred when I tried to "solve" usual diamond problem in a usual way - using virtual inheritance:
A
/ \* both virtual
B C
\ /
D
However my base class A doesn't have default constructor, so I was to call it manually from D. However when I try to add a class E into this diamond as C-inherited
A
/ \* both virtual
B C
\ / \
D E
it is still needed to call constructor of A in E constructor manually, i.e. C doesn't what to create A from E even though there is neither multiple inheritance nor diamond A-C-E.
class A
{public:
A (int _N): N(_N) {};
void show()
{cout<<"A"<<N;}
protected:
int N;
};
class B: public virtual A
{ public:
B(int n): A(2*n) {};
void show()
{ cout<<"B"<<N;}
};
class C: public virtual A
{ public:
C(int n): A(3*n) {};
void show()
{ cout<<"C"<<N;}
};
class D: public B,C
{ public:
D(): B(1), C(2), A(3) {};
void show()
{ cout<<"D"<<N;}
};
class E: public virtual C
{ public:
E(): C(1) {};
void show()
{ cout<<"E"<<N;}
};
int main()
{D d; // OK
A *a = &d;
a->show();
E e; // NOT OK, no function A::A() to call in E::E()
A *a2 = &e;
a2->show();
return 0;
}
Is it possible to solve this issue without calling constructor of A from E? I need C to do it properly :-).
Or is it possible not to try to solve diamond problem at all:
A A
| | no virtual at all
B C
\ / \
D E
and still try to declare object of class D with two instances of A but telling compiler to use A of C when colling from D each time? When I try to add
using C::A
into the declaration of D it still produce error of unambiguous base A.
Is it possible to solve this issue without calling constructor of A from E? I need C to do it properly :-).
The constructor for the most derived class (in this case, E) is responsible for calling the constructor for any virtual base classes.
The constructor of C cannot call the constructor of A because C is not the most derived class. Virtual base classes are initialized before any direct base classes, so E must initialize by A before it can initialize C.
Yes, virtual base class constructor calls are unlike virtual function overriding:
you can override a virtual function in a derived class;
you must override a virtual function only if the function is overridden in one of the base classes but not in others;
you cannot not override the init-list for virtual base classes of the base class constructor.
This implies that:
as far as virtual function overriding is concerned, virtual inheritance does not affect single inheritance at all;
but when it comes to base class constructor calls, virtual inheritance affects every derived class.