声明符概述
声明符是指定对象或函数名称的声明的组成部分。 声明符还指定是否命名对象是对象、指针、引用还是数组。 尽管声明符不指定基类型,但它们会修改基类型中的类型信息以指定派生类型,如指针、引用和数组。 声明符应用于函数,与类型说明符(用于完全指定函数的返回类型是对象、指针还是引用)的工作方式相同。 (声明中讨论的说明符涉及类型和存储类等属性。 本节和 Microsoft 专用修饰符中讨论的修饰符用于修改声明符。)下图显示 MyFunction 的完整声明,并对声明的各个组成部分进行了标注。
说明符、修饰符和声明符
Microsoft 专用
大多数 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 )
- 而 pointer-operator 是以下项之一:
* [cv-qualifiers]
& [cv-qualifiers]
:: nested-name-specifier * [cv-qualfiers]
由于一个声明符可能包含多个声明符,因此可以使用上述规则来构造更复杂的派生类型,如指针数组和返回函数指针数组的函数。 若要制定构造的所有步骤,请以呈现基数据类型的标识符开头,并应用上面的语法规则(将上一个表达式作为 declarator)。 应用语法规则的顺序应该与用英语表示表达式的方法相反。 如果将 pointer-operator 语法规则应用于某个数组或函数表达式,并且你需要指向该数组或函数的指针,请使用括号,如下表中的最后一行所示。
以下示例显示了“指向‘指向 int 的 10 个指针的数组’的指针”的构造。
文字表达式 |
声明符 |
应用的语法规则 |
---|---|---|
|
1 |
|
指针 |
|
5 |
10 的数组 |
|
4 |
指针 |
|
6,然后 5 |
当使用多个指针、引用、数组或函数修饰符时,声明符可能变得十分复杂。 主题解释更复杂的声明符介绍了如何阅读更复杂的声明符语法。 该主题同时适用于 C 和 C++,但在 C++ 中,无论在任何位置使用 * 来指示指针,都可以使用 MyClass::* 等限定名来指定指向类成员的指针。