Является ли следующее эквивалентным предварительному объявлению? - PullRequest
3 голосов
/ 05 февраля 2012

Это связано с недавним вопросом .

В основном следующий код:

class A
{
    class B* b;
    B* c;
};

компилируется, хотя class B не объявлено или не объявлено заранееЭтот синтаксис эквивалентен предварительному объявлению?Есть ли различия?

Ответы [ 3 ]

9 голосов
/ 05 февраля 2012

Вы можете объявить тип и объект в одном объявлении.

class B* b;

Объявляет тип B и объект b, который имеет указатель типа на B. Тип является неполным и ищется в той области, в которой он встречается, если при поиске не удается найти существующее объявление для класса, тогда тип присваивает имя типу в ближайшей охватывающей области пространства имен (строго не класс-не-функция-прототип область действия, которая обычно является пространством имен). Объект является членом области, в которой появляется объявление (в данном случае class A).

В большинстве случаев чаще объявлять полный тип и объект вместе, в этом случае тип иногда остается анонимным. Э.Г.

struct { int a; int b; } x;

Соответствующими частями стандарта для правил определения имен являются 7.1.5.3 [dcl.type.elab] Разработанные спецификаторы типов / 2 и ссылки на разделы в 3.4.4 и 3.3.1:

3.4.4 описывает, как происходит поиск имени для идентификатора в подробном спецификаторе типа . Если идентификатор преобразуется в имя класса или имя-перечисления , уточненный тип-спецификатор вводит его в объявление Точно так же спецификатор простого типа вводит имя-типа . Если идентификатор преобразуется в typedef-name или шаблон type-параметр , подробный спецификатор типа неверно сформирован , [...] Если при поиске имени не найдено объявление для имени, подробный спецификатор типа является некорректным, если он не имеет простой формы идентификатор ключа класса в этом случае идентификатор объявляется, как описано в 3.3.1.

1 голос
/ 05 февраля 2012

Я хотел бы добавить несколько деталей к ответу Charles Bailey :

class A
{
public:
    class B * b;
    class C {} *c;
    int d;
} a;

B* globalB;
// C* globalC;  identifier "C" is undefined here

int main(int argc, char *argv[])
{
    a.d = 1;
    cout << a.d;
}

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

Это означает, что тип B определенвыходит за рамки A, что позволяет определить переменную globalB.Если вы не хотите, чтобы B был определен вне области действия A, вы можете использовать {} так же, как он используется с типом C в моем примере.

Кстати, этопример верный и вывод его: 1

1 голос
/ 05 февраля 2012

Нет, это объявление указателя на B. Вы здесь не декларируете B, а только указатель на него, и в этом нет ничего ожидающего.

Редактировать : Я ошибся, извините. Смотрите другой ответ.

...