Поиск имени квалифицированного базового класса

Рассмотрим этот код:

#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 как член базового класса и перестает смотреть.

Другие вопросы по тегам