Подтвердить что ты не робот

Неявно вызов конструктора недоступного виртуального базового класса

Рассмотрим приведенный ниже код. И g++, и clang++ жалуются (правильно), что конструктор A(int) является приватным в классе D. Обратите внимание, что поскольку A является виртуальным базовым классом D, A должен быть инициализирован в mem-инициализаторе класса D, наиболее производном классе, согласно § 12.6.2/7 в С++ 11. См. живой пример.

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;
}

Но оба компилятора не утруждают себя тем фактом, что конструктор по умолчанию для класса A также является private в D, то есть как компилировать, так и выполнять код обычно, если мы определяем конструктор для D как следует:

D() : C(3) {}

И это неправильно, насколько я могу судить.

Обратите внимание, что оба компилятора не могут скомпилировать (правильно), если мы определим:

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

Ответ 1

Но оба компилятора не беспокоятся о том, что конструктор по умолчанию для класса A также является закрытым в D,

Нет, этот конструктор по умолчанию не является приватным. Базовый класс A является закрытым, но его конструктор по умолчанию является общедоступным.

И почему он работает: при присвоении имен базовым классам в инициализаторе ctor должны быть доступны именованные базовые классы, поскольку управление доступом применяется к именам и несколько специальных исключений, когда стандарт говорит, что неявно называемые функции по-прежнему имеют чтобы быть доступным.

Когда базовые классы неявно построены, эти базовые классы не называются. Они просто инициализируются по умолчанию (за 12.6.2p8), а инициализация по умолчанию просто проверяет, доступен ли конструктор (на 8.5p7).

Вы можете сказать, что проблема связана с именем базового класса, не используя частное унаследованное имя базового класса, но используя глобально доступное имя ::A:

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

Живой пример