11
votes

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) {}
1
You might want to add a live example that shows the case your are puzzled about i.e. D() : C(3) {}Shafik Yaghmour
@RSahu Even for the case D(): C(3) {} pointed above? I'm asking this because I really don't know the difference between the compiler I used in Coliru (the standard std=C++11) and 4.7.3 that you mentioned aboveBelloc
@RSahu With D() : C(3), I get no error with GCC 4.7.4. Which command-line options are you using with 4.7.3 to get an error for that?user743382
I got the same error error: 'class A A::A' is inaccessible on ideone: ideone.com/n9ywWodrescherjm
@ShafikYaghmour Here you go: coliru.stacked-crooked.com/a/df0b851b4f6ab1acBelloc

1 Answers

8
votes

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