|
|
Описание класса порождает новый тип. Например, ниже описываются три переменные трех различных типов:
struct X { int a; }; struct Y { int a; }; X a1; Y a2; int a3;
Отсюда следует, что такие присваивания приводят к несоответствию типов:
a1 = a2; // ошибка: Y присваивается X
a1 = a3; // ошибка: int присваивается X
Ниже описывается перегрузка ($$R.13) функции f(), а не просто повторное описание той же функции:
int f(X); int f(Y);
По той же причине нельзя дважды определять класс, это видно из примера ниже, где дважды определен S:
struct S { int a; }; struct S { int a; }; // ошибка, повторное определение
Описание класса включает имя класса в ту область видимости, внутри которой оно произошло, и закрывает любой класс, объект, функцию или другое описание этого имени в объемлющей области видимости ($$R.3.2). Если имя класса описано в такой области видимости, где уже был описан объект с таким же именем, функция или элемент перечисления, то обращаться к классу можно только с помощью конструкции спецификация-сложного-типа ($$R.7.1.6), например:
struct stat { // ... }; stat gstt; // просто `stat' используется для // определения переменной int stat(struct stat*); // переопределение `stat' как функции void f() { struct stat* ps; // нужен префикс struct // для задания структуры stat // ... stat(ps); // вызов stat() // ... }
Конструкция спецификация-сложного-типа вместе со служебным-словом-класса, но без описания объекта или функции также может служить для задания имени класса, как и описание класса, однако в этом случае класс не считается определенным, например:
struct s { int a; }; void g() { struct s; // скрывает глобальную структуру `s' s* p; // используется локальная структура `s' struct s { char* p; }; // описание локальной структуры `s' }
Такие правила позволяют классам ссылаться друг на друга при их описании, пример,
class vector; class matrix { // ... friend vector operator*(matrix&, vector&); }; class vector { // ... friend vector operator*(matrix&, vector&); };
Описание friend (дружественные функции) обсуждается в $$R.11.4, а
функция operator в $$R.13.4. Если класс, указанный как друг, пока
еще не описан, его имя считается принадлежащим той же области
видимости, в которой находится имя класса, содержащего описание
friend ($$R.11.4).
В описании объектов или функций можно также использовать
конструкцию спецификация-сложного-типа ($$R.7.1.6). Ее использование
отличается от описания класса тем, что если класс, чье имя указано
в спецификации, находится в текущей области видимости, то имя из
этой спецификации будет ссылаться на него, например:
struct s { int a; } void g() { struct* s p = new s; // обращение к глобальной `s' p->a = 1; }
Имя считается описанным сразу же после появления его идентификатора в описании. Отсюда следует, что в описании
class A * A;
A в начале задается, как имя класса, а затем оно переопределяется как имя указателя на объект этого класса, поэтому для обозначения этого класса следует использовать спецификацию-сложного типа class A. Такое "трюкачество" с именами может вызвать недоумение, и лучше его избегать. Конструкция имя-typedef ($$R.7.1.3) обозначает класс и считается именем-класса, см. также $$R.7.1.3.
| |