Определение класса вводит новый тип. [ Example:
struct X { int a; }; struct Y { int a; }; X a1; Y a2; int a3;
объявляет три переменные трех разных типов. Это означает, что
a1 = a2; // error: Y assigned to X a1 = a3; // error: int assigned to X
несоответствия типов, и что
int f(X); int f(Y);
объявить overloaded функцию, f() а не просто одну функцию f() дважды. По той же причине,
struct S { int a; };
struct S { int a; }; // error, double definition
неправильно сформирован, потому что он определяет S дважды. ] — end example
Объявление класса вводит имя класса в область, в которой оно объявлено, и скрывает любой класс, переменную, функцию или другое объявление с этим именем во вложении scope. Если имя класса объявлено в области, где также объявлены переменная, функция или перечислитель с тем же именем, тогда, когда оба объявления находятся в области видимости, на класс можно ссылаться только с помощью elaborated-type-specifier([basic.lookup.elab]). [ Example:
struct stat { // ... }; stat gstat; // use plain stat to define variable int stat(struct stat*); // redeclare stat as function void f() { struct stat* ps; // struct prefix needed to name struct stat stat(ps); // call stat() }
— end example ] A, состоящий исключительно из, является либо повторным объявлением имени в текущей области, либо прямым объявлением идентификатора как имени класса. Он вводит имя класса в текущую область видимости. [declarationclass-key identifier; Example:
struct s { int a; }; void g() { struct s; // hide global struct s with a block-scope declaration s* p; // refer to local struct s struct s { char* p; }; // define local struct s struct s; // redeclaration, has no effect }
— end example ] [ Note: Такие объявления позволяют определять классы, которые ссылаются друг на друга. [ Example:
class Vector; class Matrix { // ... friend Vector operator*(const Matrix&, const Vector&); }; class Vector { // ... friend Vector operator*(const Matrix&, const Vector&); };
Объявление friends описано в [class.friend], операторные функции - в [over.oper]. ] ] — end example — end note
[ Note: An elaborated-type-specifierтакже может использоваться type-specifierкак часть объявления. Он отличается от объявления класса тем, что, если класс с подробным именем находится в области видимости, разработанное имя будет ссылаться на него. ] [ — end note Example:
struct s { int a; }; void g(int s) { struct s* p = new struct s; // global s p->a = s; // parameter s }
— end example ]
[ Note: Объявление имени класса вступает в силу сразу после того, как identifierбудет замечено в определении класса или elaborated-type-specifier. Например,
class A * A;
first указывает, A что это имя класса, а затем переопределяет его как имя указателя на объект этого класса. Это означает, что class A для ссылки на класс необходимо использовать разработанную форму . Такой артистизм с именами может сбивать с толку, и его лучше избегать. ] — end note
Имя typedef-nameтипа класса или его cv-квалифицированная версия также является class-name. Если a, typedef-nameкоторый именует тип класса cv-Qualified, используется там, где a class-nameтребуется, cv-квалификаторы игнорируются. А typedef-nameне должно использоваться как identifierв class-head.