Описание класса порождает новый тип. Например, ниже описываются три переменные трех различных типов:
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.
список-членов:
описание-члена список-членов opt
спецификация-доступа : список-членов opt
описание-члена:
спецификации-описания opt список-описателей-членов opt;
определение-функции ; opt
уточненное-имя ;
список-описателей-членов:
описатель-члена
список-описателей-членов , описатель-члена
описатель-члена:
описатель спецификация-чистой opt
идентификатор opt: выражение-константа
спецификация-чистой:
= 0
С помощью конструкции список-членов можно описать данные, функции, классы, элементы перечисления (§R.7.2), битовые поля, друзей (§R.11.4) и имена типов (§R.7.1.3, §R.9.1). Кроме того, список-членов может содержать описания, устанавливающие доступ к именам членов, см. §R.11.3. Никакой член не может быть дважды описан в списке-членов. Список-членов определяет все множество членов данного класса, т.е. нельзя добавить еще один член в каком-либо другом описании.
Читать дальше