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

Что такое синтаксис С++ "A:: B: A {};" имею в виду

Что означает синтаксис С++ struct A::B:A {};? Где это определение имени (или доступ), описанное в стандарте С++?

#include <iostream>

struct B;

struct A {
    struct B;
};

struct A::B:A {
};

int main() {
    A::B::A::B b;
    std::cout<<"Sizeof A::B::A::B is " << sizeof(A::B::A::B)<<std::endl;
    return 0;
}
4b9b3361

Ответ 1

Это определение

struct A {
    struct B;
};

Определяет struct A с объявлением вложенной структуры B 1. Полноценное имя B равно A::B, вы можете сказать, что B находится внутри "пространства имен" A. Тогда это:

struct A::B : A { // Note I added spaces
};

Является ли определение A::B, а единственный : указывает, что он получен из A.

Теперь интересная часть A::B::A::B. Разрежьте его:

  • A::B обозначает вложенную структуру.
  • A::B::A получает доступ к имени введенного класса A внутри B. Инъекция связана с наследованием.
  • A::B::A::B снова введет вложенную структуру B в A.

И вы можете продолжить ad-infinitum или, по крайней мере, до тех пор, пока ваш компилятор не выполнит свой лимит перевода 2.

Увлекательное интеллектуальное упражнение, но избегайте, как чума в реальном коде.


[class.qual]/1 объясняет, как работает поиск

Если спецификатор вложенного имени квалифицированного идентификатора назначает класс, имя, указанное после определения вложенного имени-спецификатора в объем класса ([class.member.lookup]), за исключением случаев перечислено ниже. Название должно представлять один или несколько членов этого класса или одного из его базовых классов (раздел [class.derived]).

И вышеприведенный текст позволяет нам назвать базовый класс, потому что [class]/2

Имя класса также вставляется в область самого класса; это известно как имя введенного класса. Для доступа проверка, имя введенного класса обрабатывается так, как если бы оно было общедоступным имя участника.

Вышеприведенное ясно говорит о том, что при запуске полного имени с A:: вы можете указать член или базовый класс. Поскольку A не имеет оснований, вы можете указать только A::B ( "тип члена" ). Но A::B также назначает класс. Поэтому мы можем указать базу или ее часть с помощью A::B::, что позволяет нам называть A::B::A. Теперь промойте и повторите.


<суб > 1 - Обратите внимание на это совсем другое B. Совсем не связано с глобальным struct B.
2 - рекомендуемый минимум 256 в соответствии с [implimits]/2.36

суб >

Ответ 2

Прежде всего struct B; является прямым объявлением struct B в глобальном пространстве имен. Это может сбивать с толку, потому что в этом примере оно действительно не имеет значения. К этому глобальному B можно получить доступ как ::B или как только B.

struct A {
    struct B;
};

Является определением struct A в глобальном пространстве имен с прямым объявлением вложенной структуры B (не такой, как ранее объявленный B в глобальном пространстве имен). К этому вложенному B можно получить доступ как ::A::B или A::B.

struct A::B:A {
};

Является определением вложенной структуры B структуры A, которая наследуется от A (с отсутствием спецификатора доступа). Его можно переписать следующим образом:

struct A::B
:   public A
{
};

Обратите внимание, что определение определения вложенной структуры B внутри определения A, как это, не будет работать:

struct A {
    struct B: A { // error: A is incomplete at this point
    };
};

И, наконец, A::B::A ссылается на базовый класс вложенной структуры B, то есть на A, поэтому A::B::A::B эквивалентен просто A::B.