Поделиться через


Общие сведения о деклараторах

Деклараторы — это компоненты объявления, которые определяют имена объектов или функций. Деклараторы также указывают, является ли именованный объект массивом, объектом, указателем или ссылкой. Хотя деклараторы и не задают базовый тип, однако они изменяют хранящуюся в нем информацию о типе, что позволяет определять производные типы, например указатели, ссылки и массивы. Применительно к функциям декларатор действует на спецификатор типа. Это дает возможность полностью определить тип возвращаемого функцией значения: объект, указатель или ссылка. (Спецификаторы, о которых говорится в разделе Объявления, передают такие свойства, как тип и класс хранения. Модификаторы, которые рассматриваются в этом разделе и в разделе Модификаторы, используемые в системах Microsoft, изменяют деклараторы.) На следующем рисунке представлено полное объявление функции MyFunction и указаны входящие в него компоненты.

Спецификаторы, модификаторы и деклараторы

Модификаторы, спецификаторы и деклараторы

Блок, относящийся только к системам Microsoft

Большинство ключевых слов расширений Microsoft можно использовать в качестве модификаторов для создания производных типов; они не являются ни спецификаторами, ни деклараторами. (См. раздел Модификаторы, используемые в системах Microsoft.)

Завершение блока, относящегося только к системам Майкрософт

В синтаксисе объявления деклараторы указываются после необязательного списка спецификаторов. Спецификаторы рассматриваются в разделе Объявления. Объявление может содержать несколько деклараторов, но каждый из них объявляет только одно имя.

В следующем примере видно, как сочетаются спецификаторы и деклараторы, из которых состоит полное объявление:

const char *pch, ch;

В приведенном выше объявлении ключевые слова const и char образуют список спецификаторов. Помимо них перечислены два декларатора: *pch и ch. Объявление, в котором объявлено несколько сущностей, состоит из спецификатора типа, за которым следует список деклараторов, разделенных запятыми. Объявление завершается точкой с запятой.

Деклараторы для простых объектов

Декларатор простого объекта, например int или double, содержит только имя. К нему могут добавляться необязательные круглые скобки.

int i; // declarator is i

int (i); // declarator is (i)

Деклараторы для указателей, ссылок и массивов

Если перед именем находится оператор указателя, то объект создается как указатель или ссылка. Оператор * объявляет имя в качестве указателя, а оператор & — в качестве ссылки.

int *i; // declarator is *i
int **i; // declarator is **i;
int &i = x; // declaratory is &i

Если к указателю добавлен спецификатор const или volatile, он становится константным или изменяемым соответственно. Использование этих спецификаторов в деклараторе (в отличие от спецификатора типа) позволяет изменить свойства самого указателя, а не его объекта.

char *const cpc; // const pointer to char 
const char *pcc; // pointer to const char 
const char *const cpcc; // const pointer to const char

Дополнительные сведения см. в разделе Указатели const и volatile.

Указатель на член класса или структуры объявляется с соответствующим спецификатором вложенного имени:

int X::* pIntMember; 
int ::X::* pIntMember; // the initial :: specifies X is in global scope
char Outer::Inner::* pIntMember; // pointer to char in a nested class

Если после имени стоят квадратные скобки, в которые заключено необязательное константное выражение, то объект создается как массив. Несколько пар квадратных скобок подряд объявляют дополнительные размерности массива.

int i[5]; // array with five elements of type int numbered from 0 to 4
int i[]; // array of unknown size
char *s[4]; // array of pointers to char
int i[2][2]; // two dimensional array

Деклараторы для функций

Круглые скобки, расположенные после имени и окружающие список аргументов, позволяют объявить функцию. В следующем примере объявляется функция, которая возвращает значение типа int, и три аргумента типа int.

int f(int a, int b, int c);

Сведения о списках аргументов см. в разделе Объявления функций.

Чтобы объявить указатель или ссылку на функцию, необходимо добавить перед ее именем оператор указателя или ссылки, как показано ниже. Скобки, которые обычно являются необязательными, необходимы для того, чтобы указатель на функцию можно было отличить от функции, которая возвращает указатель:

int (*pf)(int); // pointer to function returning int
int *f(int i); // function returning pointer to int
int (&pf)(int); // reference to function 

Указатели на функции-члены можно отличить по вложенным спецификаторам имен:

int (X::* pmf)(); // pointer to member function of X returning int
int* (X::* pmf)(); // pointer to member function returning pointer to int

См. также раздел Указатели на члены.

Функции и объекты в одном и том же объявлении

Объявлять функции и объекты можно в одном и том же объявлении. Это делается следующим образом:

int i, *j, f(int k);  // int, pointer to int, function returning int

В некоторых случаях синтаксис может вводить в заблуждение. Рассмотрим следующее объявление:

int* i, f(int k);  // pointer to int, function returning int (not int*)

Оно может выглядеть как объявление указателя типа int и функции, возвращающей значение типа int*, но на самом деле это не так. Это связано с тем, что оператор * входит в декларатор i, а не f.

Упрощение синтаксиса декларатора при помощи оператора typedef

Лучше всего, однако, использовать ключевое слово typedef или круглые скобки с ключевым словом typedef. Рассмотрим следующее объявление массива указателей на функции:

//  Function returning type int that takes one 
//   argument of type char *.
typedef int (*PIFN)( char * );
//  Declare an array of 7 pointers to functions 
//   returning int and taking one argument of type 
//   char *.
PIFN pifnDispatchArray[7];

Аналогичное объявление можно записать и без ключевого слова typedef, но оно будет весьма сложным, так что вероятность появления ошибки нивелирует все преимущества:

int ( *pifnDispatchArray[7] )( char * );

Дополнительные сведения о ключевом слове typedef см. в разделе Спецификатор typedef.

Указатели, ссылки, массивы одного базового типа можно объединить в одном объявлении (разделив их запятыми), как в следующем примере:

int a, *b, c[5], **d, &e=a;

Более сложный синтаксис декларатора

  • Деклараторы указателей, ссылок, массивов и функций можно объединять. Это позволит объявлять такие объекты, как массивы указателей на функции, указатели на массивы и т. д.

  • Приведенная ниже рекурсивная грамматика полностью описывает синтаксис декларатора указателя.

  • Декларатор (declarator) определяется одним из следующих правил:

1. identifier 
2. qualified-name 
3. declarator ( argument-list ) [cv-qualfiers] [exception-spec]
4. declarator [ [ constant-expression ] ] 

5. pointer-operator declarator 
6. ( declarator )
  • А оператор-указателя) — одним из следующих:
* [cv-qualifiers]
& [cv-qualifiers]
:: nested-name-specifier * [cv-qualfiers]

Поскольку любой декларатор может содержать другие деклараторы, то при помощи приведенных выше правил можно создавать более сложные производные типы, например массивы указателей или функции, возвращающие массивы указателей на функции. Чтобы сформировать каждую часть этой конструкции, сначала укажите идентификатор, представляющий базовый тип данных, а затем примените правило синтаксиса с приведенным выше выражением в качестве декларатора (declarator). Порядок, в котором применяются правила синтаксиса, должен быть обратным тому, в каком выражения формулируются в английском языке. Если вам необходимо создать указатель на массив или функцию и вы применяете правило синтаксиса оператора-указателя к выражению массива или функции, используйте скобки, как в последней строке приведенной ниже таблицы.

В следующем примере показано создание указателя на массив из десяти указателей на целочисленное значение.

Словесное выражение

Декларатор

Применяемое правило синтаксиса

i

1

указателей на

*i

5

массив из 10

(*i)[10]

4

указатель на

*((*i)[10])

6, а затем 5

Если используется несколько модификаторов указателя, ссылки, массива или функции, то деклараторы могут становиться довольно сложными. В разделе Интерпретация более сложных деклараторов рассказывается о том, как читать более сложный синтаксис деклараторов. Этот раздел относится как к языку C, так и к языку C++. Тем не менее в C++ во всех случаях, когда для обозначения указателя используется оператор *, определять указатель на член класса можно при помощи полного имени, например MyClass::*.

См. также

Ссылки

Деклараторы