Все ли производные классы из иерархии требуют доступа к виртуальному базовому классу?

Когда я пытаюсь скомпилировать следующий код:

class A {
public:
A(int v) : virt(v) { }
int virt;
int getVirt(void) const { return virt; }
};

class B : private virtual A {
protected:
B(int v) : A(v) { }
using A::getVirt;
};

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

class D : public C {
public:
D(void) : C(3) { }
using C::getVirt;
};

#include <iostream>

int main(int argc, char *argv[]) {
D d;
std::cout << "The number is: " << d.getVirt() << std::endl;

return 0;
}

Я получаю ошибку о том, что D не создает A; это верно? Если виртуальная база встроена в иерархию, все ли производные классы также должны быть производными от этой базы, чтобы они могли вызывать параметрический конструктор виртуальной базы?

Кстати, вот ошибки, созданные G ++:

Main.cpp: In constructor ‘D::D()’:
Main.cpp:22:18: error: no matching function for call to ‘A::A()’
Main.cpp:22:18: note: candidates are:
Main.cpp:3:5: note: A::A(int)
Main.cpp:3:5: note:   candidate expects 1 argument, 0 provided
Main.cpp:1:7: note: A::A(const A&)
Main.cpp:1:7: note:   candidate expects 1 argument, 0 provided

6

Решение

Как упоминает Керрек С.Б., вы необходимость инициализировать A в конструкторе для D,

Тем не менее, вы также должны явно указать компилятору, что вы не доступа A из его (частного) производного контекста с помощью оператора видимости.

class D : public C {
public:
D(void) : ::A(3), C(3) { }
//            ^^ Access this constructor from a global context
using C::getVirt;
};

Это также означает, что ваш конструктор должен быть публичным, как это уже имеет место с вашим кодом.

1

Другие решения

Это не имеет ничего общего с контролем доступа (по крайней мере, в первую очередь). Скорее, вы должны понимать, как работают виртуальные базы: подобъект виртуальной базы инициализируется наиболее производный учебный класс. Поскольку вы не упоминаете A в списке инициализатора конструктора D, конструктор по умолчанию используется, но не существует.

Чтобы это исправить, инициализируйте A правильно в D:

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

Когда ты сказал A(3)Поиск имени выполняется в соответствии с 12.6.2 / 2:

В мем-инициализатор-идентификатор начальный неквалифицированный идентификатор ищется в области видимости класса конструктора и, если не найден в этой области, он ищется в области видимости, содержащей определение конструктора.

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

6

По вопросам рекламы [email protected]