Что касается второго вопроса, это, вероятно, потому, что вы не делаете его неявным образом определенным . Если конструктор просто неявно объявлен, ошибки нет. Пример:
struct A { A(int); };
struct B : A { };
// goes fine up to here
// not anymore: default constructor now is implicitly defined
// (because it's used)
B b;
Ваш первый вопрос - это зависит от того, какое имя использует компилятор. Я понятия не имею, что указывает стандарт, но этот код, например, является правильным, потому что внешнее имя класса (вместо унаследованного имени класса) доступно:
class A {};
class B: private virtual A {};
class C: public B { C(): ::A() { } }; // don't use B::A
Возможно, стандарт недостаточно определен на данный момент. Придется посмотреть.
Кажется, нет никаких проблем с кодом. Кроме того, есть указание на то, что код действителен. (Виртуальный) подобъект базового класса инициализируется по умолчанию - нет текста, который подразумевает, что поиск имени для имени класса находится внутри области C
. Вот что говорит Стандарт:
12.6.2/8
(C ++ 0x)
Если данный нестатический элемент данных или базовый класс не назван с помощью mem-initializer-id (включая регистр
где нет mem-initializer-list, потому что конструктор не имеет ctor-initializer), а сущность не является виртуальным базовым классом абстрактного класса
[...] в противном случае объект инициализируется по умолчанию
И C ++ 03 имеет похожий текст (менее понятный текст - он просто говорит, что его конструктор по умолчанию вызывается в одном месте, а в другом он делает его зависимым от того, является ли класс POD). Чтобы компилятор по умолчанию инициализировал подобъект, ему просто нужно вызвать конструктор по умолчанию - нет необходимости сначала искать имя базового класса (он уже знает , какая база считается).
Считайте, что этот код определенно должен быть действительным, но он потерпит неудачу, если будет выполнено это (см. 12.6.2/4
в C ++ 0x)
struct A { };
struct B : virtual A { };
struct C : B, A { };
C c;
Если конструктор по умолчанию компилятора будет просто искать имя класса A
внутри C
, он будет иметь неоднозначный результат поиска в отношении того, какой подобъект инициализируется, потому что и не виртуальный A
, и Виртуальные A
имена классов найдены. Если ваш код предназначен для неправильной формы, я бы сказал, что Стандарт, безусловно, нуждается в уточнении.
Для конструктора обратите внимание, что 12.4/6
говорит о деструкторе C
:
Все деструкторы вызываются так, как будто на них ссылается квалифицированное имя, то есть игнорируются любые возможные виртуальные переопределения деструкторов в более производных классах.
Это можно интерпретировать двумя способами:
- вызов A :: ~ A ()
- вызов :: A :: ~ A ()
Мне кажется, что Стандарт здесь менее ясен. Второй способ сделает его действительным (3.4.3/6
, C ++ 0x, потому что оба имени класса A
ищутся в глобальной области видимости), тогда как первый сделает его недействительным (поскольку оба A
найдут унаследованные имена классов). Это также зависит от того, с какого подобъекта начинается поиск (и я считаю, что нам нужно будет использовать подобъект виртуального базового класса в качестве начальной точки). Если это идет как
virtual_base -> A::~A();
Затем мы непосредственно найдем имя виртуального базового класса как публичное имя, потому что нам не нужно будет проходить через границы производного класса и находить имя как недоступное. Опять же, рассуждения похожи. Рассмотрим:
struct A { };
struct B : A { };
struct C : B, A {
} c;
Если деструктор просто вызовет this->A::~A()
, этот вызов будет недействительным из-за неоднозначного результата поиска A
как унаследованного имени класса (вы не можете ссылаться на любую нестатическую функцию-член прямой базы Объект класса из области C
, см. 10.1/3
, C ++ 03). Он должен уникальным образом идентифицировать имена участвующих классов и начинаться с ссылки на подобъект класса, например a_subobject->::A::~A();
.