Чтение онлайн

ЖАНРЫ

Справочное руководство по C++

Страустрап Бьярн

Шрифт:

Спецификации static и extern могут применяться только к именам объектов или функций или к анонимным объединениям. Внутри блока недопустимы описания функций со спецификацией static или формальных параметров со спецификацией static или extern. Статические члены класса описываются в §R.9.4. Спецификация extern недопустима для членов класса.

Имя со спецификацией static подлежит внутреннему связыванию. Объекты, описанные как const, подлежат внутреннему связыванию, если только они не были описаны с внешней связью. Имя со спецификацией extern подлежит внешнему связыванию, если только ранее оно не было описано с внутренней связью. Имя с файловой областью видимости

и без спецификации-класса-памяти подлежит внешнему связыванию, если только ранее оно не было описано с внутренней связью или со спецификацией const. В смысле связывания для функций, не являющихся членами, спецификация inline эквивалентна static (§R.3.3). Для одного имени все его спецификации, определяющие связывание, должны быть согласованы. Например,

static char* f; // f имеет внутреннее связывание

char* f // f все еще внутреннее

{/*… */}

char* g; // g имеет внешнее связывание

static char* g // ошибка: противоречие в связывании

{/*… */}

static int a; // `a' имеет внутреннее связывание

int a; // ошибка: второе определение

static int b; // `b' имеет внутреннее связывание

extern int b; // `b' все еще внутреннее

int c; // `c' имеет внешнее связывание

static int c; // ошибка: противоречие в связывании

extern int d; // `d' имеет внешнее связывание

static int d; // ошибка: противоречие в связывании

Имя неопределенного класса можно использовать в описании extern. Однако, такое описание нельзя использовать прежде, чем класс будет определен, например,

struct S;

extern S a;

extern S f;

extern void g(S);

void h

{

 g(a); // ошибка: S неопределено

 f; // ошибка: S неопределено

}

R.7.1.2 Спецификации функций

Некоторые спецификации можно использовать только в описании функций.

спецификация-fct:

 inline

 virtual

Спецификация inline подсказывает транслятору, что необходимо произвести подстановку тела функции вместо обычной реализации вызова функции. Подсказка может игнорироваться. В случае функций, не являющихся членами, спецификация inline дополнительно устанавливает для функции внутреннее связывание (§R.3.3). Функция (§R.5.2.2, §R.8.2.5), определенная в описании класса, имеет по умолчанию спецификацию inline.

Функция-член со спецификацией inline должна иметь в точности такое же определение в каждой единице трансляции, где она появляется.

Функцию-член не обязательно явно описывать со спецификацией inline при описании класса, чтобы она трактовалась как подстановка. Если спецификации inline не было, связывание будет внешним, если только определение со спецификацией inline не появится перед первым вызовом функции.

class X {

public:

 int f;

 inline int g; // X::g
имеет внутреннее связывание

 int h;

};

void k(X* p)

{

 int i = p-›f; // теперь X::f внешнее связывание

 int j = p-›g;

 //…

}

inline int X::f // ошибка: вызов до определения

 // как inline

{

 //…

}

inline int X::g

{

 //…

}

inline int X::h // теперь X::h имеет внутреннее связывание

{

 //…

}

Спецификация virtual может использоваться только в описаниях нестатических функций-членов при описании класса (см. §R.10.2).

R.7.1.3 Спецификация typedef

Описания со спецификацией typedef задают идентификаторы, которые позднее могут использоваться для обозначения основных или производных типов. Спецификация typedef недопустима в определении-функции (§R.8.3).

имя-typedef:

 идентификатор

В пределах области видимости (§R.3.2) описания typedef любой идентификатор, появляющийся в части любого из описателей, становится синтаксически эквивалентным служебному слову и обозначает тип, связанный с данным идентификатором, как описано в §R.8. Таким образом, имя-typedef является синонимом другого типа. В отличие от описания класса (§R.9.1) имя-typedef не добавляет нового типа. Например, после описания

typedef int MILES, *KLICKSP;

конструкции

MILES distance;

extern KLICKSP metricp;

являются законными описаниями, тип distance есть int, а у metricp тип "указатель на int".

С помощью typedef можно переопределить имя так, чтобы оно опять обозначало тип, на который уже ссылалось, причем даже в той области видимости, в которой тип был первоначально описан, например,

typedef struct s {/*… */} s;

typedef int I;

typedef int I;

typedef I I;

Безымянный класс, который определяется в typedef, получает в качестве своего имени имя, использованное в typedef, например,

typedef struct {/*… */} S; // имя структуры стало S

С помощью описания typedef нельзя переопределить имя типа, описанного в этой же области видимости, так, чтобы оно обозначало другой тип, например,

class complex {/*… */};

typedef int complex; // ошибка: переопределение

Поделиться с друзьями: