Это связано с недавним вопросом.
В основном следующий код:
class A
{
class B* b;
B* c;
};
компилируется, хотя class B
не объявляется и не объявляется вперед. Эквивалентен ли этот синтаксис прямому объявлению? Есть ли отличия?
Это связано с недавним вопросом.
В основном следующий код:
class A
{
class B* b;
B* c;
};
компилируется, хотя class B
не объявляется и не объявляется вперед. Эквивалентен ли этот синтаксис прямому объявлению? Есть ли отличия?
Вы можете объявить тип и объект в одном объявлении.
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-parameter, расширенный-описатель-тип плохо сформирован. [...] Если поиск имени не находит объявления для имени, спецификатор детализированного типа неправильно сформирован, если он не имеет простой формы идентификатор ключа класса em>, и в этом случае идентификатор объявляется, как описано в 3.3.1.
B
не является членом A
, но относится к ::B
и входит в сферу действия даже за пределами определения A
.
- person ; 05.02.2012
B
уже был в области видимости, например объявление, состоящее не более чем из class B;
, тогда оно могло относиться к вложенному классу A::B
.
- person ; 05.02.2012
void f() { struct s { struct p *ptr; } s; struct p { } p; s.ptr = &p; }
:)
- person ; 05.02.2012
Нет, это объявление указателя на B. Здесь вы не объявляете B, а только указатель на него, и в этом нет ничего особенного.
Изменить: я ошибся, извините. Смотрите другой ответ.
B
, как объяснить отсутствие ошибки в строке 3, где ключевое слово class
опущено?
- person ; 05.02.2012
c
.
- person Luchian Grigore; 05.02.2012
Я хотел бы добавить несколько деталей к ответу Чарльза Бейли:
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
g++ -std=c++98 -pedantic
это нравится. - person CB Bailey   schedule 05.02.2012B
, работать без написанияclass
), когда он принимает форму определения, как здесь. - person j_random_hacker   schedule 05.02.2012