1

How default constructor of most base class is getting called in private virtual inheritance while creating object of most derived class. But the same does not get called when mentioned in constructor initializer list of most derived class.

#include<iostream>
using namespace std;
class A
{
public:
     A() {cout << "1";}

};

class B: private virtual A
{
public:
    B() {cout << "2";}

};

class C: private virtual A
{
public:
   C() {cout << "3";}

};

class D: private B, private C
{
public:
    D() : A(), B(), C() {cout << "4";}
    //D()  {cout << "4";}

};

int main()
{
   D d1;
   cout << "\n";
}

My Problem:

For Below mentioned code

D() : A(), B(), C() {cout << "4";}

I get below compilation error:

error: 'class A A::A' is inaccessible within this context

Why A() constructor is inaccessible here?

On the other hand below mentioned code gets compiled successfully and A() constructor gets called.

D()  {cout << "4";}

Output of the program is: 1234 Means A() constructor is getting called.

So, Why is the change in behavior for calling of constructor A() in above two cases?

What I know:

(1) When I do 'Public Virtual inheritance' of B & C, then default constructor of most base class is gets called even if it's in mentioned in constructor initializer list of most derived class. Means below statement compiles. D() : A(), B(), C() {cout << "4";}

(2) In virtual Inheritance, constructor of virtual base class is called directly from most derived class's constructor.

It might be a concept issue for me of virtual inheritance. Kindly help me to understand this and share good references for that.

curiousguy
  • 8,038
  • 2
  • 40
  • 58
Gaurav
  • 161
  • 1
  • 11
  • 4
    If `A` is privately owned by `B` and `C`, `D` cannot access it. It's that simple. – Patrick Roberts May 05 '17 at 06:00
  • `A`'s constructor is inaccessible because `D` has not a subclass of type `A`, instead it derives from `B` and `C` that derive **privately** from `A`. The other way around works for you implicitly construct `C` and `B` and they implicitly construct `A`, that is something they are allowed to do being it a direct subclass. – skypjack May 05 '17 at 06:01
  • 1
    Maybe the fix would be `class D: virtual private A, private B, private C` – M.M May 05 '17 at 06:02
  • Or else just remove the `A()` call. It will happen anyway, but at the correct point, and this isn't it. You should only be calling constructors for direct base classes or instance members here. – user207421 May 05 '17 at 06:04
  • 1
    @PatrickRoberts, Then why "D() {cout << "4";}" works. How does it call A() constructor even in private inheritance? – Gaurav May 05 '17 at 06:08
  • @Gaurav Because the compiler inserts default constructor calls by default. `B()` and `C()` both call `A()`, virtually. – user207421 May 05 '17 at 06:08
  • 1
    @Gaurav because of virtual inheritance. The difference is, there, it is implicitly doing so, but you cannot explicitly tell it to do so. – Patrick Roberts May 05 '17 at 06:09
  • @EJP "_B() and C() both call A(), virtually_" what is a "virtual" call? – curiousguy May 06 '17 at 22:07
  • Looks like a compiler bug. – curiousguy May 06 '17 at 23:04

2 Answers2

0

A is private from the point of view of D, but even if it wasn't it is incorrect for D to try to construct A. It should only construct direct base classes and instance member objects. B and C will both see to the construction of A by default.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • 3
    As it is virtual inheritance, it is not incorrect for `D` to try to construct `A`, and even it should do. It is even more visible when `A` doesn't have default constructor. – Jarod42 May 05 '17 at 09:25
  • @Jarod42 No. A is not a direct subclass of D, and it is therefore not D's business to initialize it. – user207421 May 05 '17 at 09:35
  • 4
    But it uses *virtual inheritance*, so the most derived class should construct the object. [Demo](http://coliru.stacked-crooked.com/a/7cc3f7e9935fe4ef) – Jarod42 May 05 '17 at 09:41
  • "_B and C will both see to the construction of A by default._" are you saying that two constructors will try to construct the same subobject? – curiousguy May 06 '17 at 23:04
0

As was mentioned in the comments, A() cannot be explicitly called from D() because A() is a private member of B and C. private inheritance gives access to public and protected members and makes them private. Whatever was private, is not inherited. So the key point is access specifiers during inheritance, not virtual inheritance. You can try and remove virtual from your example. The program will print 12134 because virtual inheritance was providing a common base object.

In case someone wonders why 1234 (or 12134 in non-virtual case) is outputted by the program, I invite them to read about the order of construction of derived classes: https://www.learncpp.com/cpp-tutorial/order-of-construction-of-derived-classes/

honey_badger
  • 472
  • 3
  • 10
  • But removing virtual drastically changes the semantics of a class. – curiousguy Mar 31 '21 at 22:10
  • @curiousguy, true. But explicitly calling a private constructor of another class is never available. The compiler can do it for you though: https://godbolt.org/z/rjKW3s6Kd (see the object construction starting from line 66) – honey_badger Apr 02 '21 at 09:42
  • Maybe... but I doubt the implicit ctor call is more legal than the explicit call. The std is not cristal clear, but my reading is: not legal. – curiousguy Apr 03 '21 at 00:16