Failed Scientist
Failed Scientist

Reputation: 2027

C++ - Why does the default constructor work even in private inheritance

The following question brought this phenomenon to notice where the constructor is being called even in the private mode of inheritance.

I tried it on the Diamond Problem, then made it simpler by breaking the diamond rule and just keeping virtual inheritance.

Further followed this up by a simple example of a 3-level inheritance which I am showing below (C inherited by B and B inherited by C - both in private inheritance) and still the constructor of A is being called.

Shouldn't A() be private and inaccessible in C?

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

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

class C:  B
{
public:
   C(){ cout << "3"; }
};


int main()
{
   C c1;
}

Output: 123 (You can also view the code and output here)

P.S: I have tried it both with the normal case (given here) and with virtual inheritance, even with the "Diamond-Problem" - the answer is same every time.

Upvotes: 3

Views: 1017

Answers (1)

There's no virtual inheritance involved, so it's not up to C to construct A. Therefore the constructor for C invokes the constructor for B, which in turn invokes the constructor for A. There is no supposed breach of access specifiers going on.

For the virtual inheritance case, we note that construction of sub-objects that are omitted from the member initialization list is specified by

[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.

So the above clause would seem to indicate the default initialization must happen, with access specifiers supposedly discarded.

What's important to remember is that access specifiers are to limit what programs may refer to inside a class definition, they will not stop the compiler from emitting correct code, such as required by the clause above.

If however, you had attempted to explicitly call the default constructor for the virtual base, it would be ill-formed, like this:

#include<iostream>
using namespace std;
class A
{
public:
     A(){ cout <<"1";}
};
 
class B:  virtual A
{
public:
    B(){cout <<"2";}
};
 
class C:  B
{
public:
   C() : A() {cout<<"3";}
};
 
int main()
{
   C c1;
}

Which gives:

prog.cpp: In constructor ‘C::C()’:
prog.cpp:18:10: error: ‘class A A::A’ is inaccessible within this context
    C() : A() {cout<<"3";}
          ^
prog.cpp:4:1: note: declared here
 {
 ^

Why? Because now it is your program that is trying to breach access explicitly, and not the compiler doing its job.

Upvotes: 3

Related Questions