Belloc
Belloc

Reputation: 6390

Implicitly calling a constructor of an inaccessible virtual base class

Consider the code below. Both g++ and clang++ complain (correctly) that the constructor A(int) is private in class D. Note that, as A is a virtual base class of D, A has to be initialized in the mem-initializer of class D, the most derived class, according to §12.6.2/7 in C++11. See live example.

class A {
public:
    A(int i) : x(i) { }
    A() : x(1) {}
    int x;
};

class B : private virtual A {
protected:
    B(int i) : A(i) { } };

class C : public B, private virtual A {
protected:
    C(int i) : A(i), B(i) { }
};

class D : public C {
public:
    D() : A(1), C(3) { }
};

int main() {
    D d;
}

But both compilers don't bother with the fact that the default constructor for class A is also private in D, i.e., both compile and execute the code normally, if we define the constructor for D as follows:

D() : C(3) {}

And this is wrong, as far as I can tell.

Note that both compilers fail to compile (correctly) if we define:

D() : A(), C(3) {}

Upvotes: 11

Views: 1126

Answers (1)

user743382
user743382

Reputation:

But both compilers don't bother with the fact that the default constructor for class A is also private in D,

No, that default constructor isn't private. The base class A is private, but its default constructor is public.

And that's why it works: when naming base classes in the ctor-initializer, the named base classes have to be accessible, because access control applies to names, and a few special exceptions where the standard says that implicitly called functions still have to be accessible.

When base classes are implicitly constructed, those base classes are not named. They are simply default-initialized (per 12.6.2p8), and default-initialization merely checks whether the constructor is accessible (per 8.5p7).

You can tell that the problem is with the name of the base class by not using the private inherited name of the base class, but by using the globally accessible name ::A:

D() : ::A(1), C(3) { }

Live example

Upvotes: 8

Related Questions