Поиск имени квалифицированного базового класса
Рассмотрим этот код:
#include <iostream>
namespace D
{
struct S { S(){std::cout << "D::S\n";} };
}
struct S { S(){std::cout << "S\n";} };
struct X: D::S
{
X(): S() {} // (1)
// X(): D::S() {} // (2)
void f() { S s; }
};
int main() { X x; x.f(); }
Вывод из g++:
D::S
D::S
Мои вопросы:
- Как (1) работает - хотя бы имя базового класса
D::S
конкретно - Обе (1) и (2) должны работать?
- Почему
S s;
внутриf()
Ссылаться наD::S
и не::S
?
1 ответ
В теле класса D::S
имя S
относится к себе, очевидно. Это называется "имя введенного класса". Вы можете думать об этом, как будто есть открытый член typedef в D::S
со своим именем, S
,
- Как (1) работает - я хотел бы знать, что имя базового класса определенно D::S
X
происходит от D::S
потому что вы так сказали в списке базовых классов X
,
Производный класс имеет доступ к именам, объявленным в базовом классе, поэтому поиск имени в X
сначала смотрит на своих собственных членов и членов своего базового класса, затем ищет имена во внешней области видимости за пределами X
, Потому что введенное имя класса S
является членом D::S
, он найден в X
Вот почему (1) работает. Тип ::S
не найден, потому что поиск по имени находит введенное имя класса и никогда не ищет в области видимости (если он нашел ::S
код не будет компилироваться, потому что ::S
не является базовым классом X
).
В качестве аналогии рассмотрим этот пример, используя член typedef, объявленный в D::S
:
namespace D {
struct S {
struct S { S(){std::cout << "D::S\n";} };
typedef S AnotherName;
};
}
struct X : D::S {
X() : AnotherName() { }
};
Это работает, потому что имя AnotherName
находится в базовом классе и является синонимом типа базового класса, D::S
, Имя внедренного класса работает аналогично, за исключением того, что вводимое имя является собственным именем класса, S
, а не какое-то другое имя, как AnotherName
,
- Обе (1) и (2) должны работать?
Да.
(2) работает потому что D::S
является полностью квалифицированным именем S
поэтому он ссылается на тот же тип, но использует свое "полное имя", которое не-члены должны использовать для ссылки на тип.
- Почему S s; внутри f() ссылаются на D::S, а не на::S?
Потому что, как конструктор, f()
является членом X
так что поиск имени выглядит в рамках X
(и его базовые классы) сначала, и поэтому находит введенное имя класса. Никогда не видишь типа ::S
в глобальном масштабе, потому что он находит имя S
как член базового класса и перестает смотреть.