logo
volkov / C++ / Бьерн Страуструп-Справочное руководство по С++

R.9.1 Имена класса

Описание класса порождает новый тип. Например, ниже описываются

три переменные трех различных типов:

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.