声明和定义 (C++)
C++ 程序由各种实体组成,例如变量、函数、类型和命名空间。 必须先声明其中的每个实体才能使用它们。 声明指定实体的唯一名称,以及有关其类型和其他特征的信息。 在 C++ 中,声明名称的位置就是它对编译器可见的位置。 无法引用稍后在编译单元中某个位置声明的函数或类。 变量应尽可能在靠近其使用位置之前的位置声明。
下面的示例演示了一些声明:
#include <string>
int f(int i); // forward declaration
int main()
{
const double pi = 3.14; //OK
int i = f(2); //OK. f is forward-declared
C obj; // error! C not yet declared.
std::string str; // OK std::string is declared in <string> header
j = 0; // error! No type specified.
auto k = 0; // OK. type inferred as int by compiler.
}
int f(int i)
{
return i + 42;
}
namespace N {
class C{/*...*/};
}
在第 5 行,声明了 main
函数。 在第 7 行,声明并初始化了名为 pi
的 const
变量。 在第 8 行,使用函数 f
生成的值声明并初始化了整数 i
。 由于第 3 行中的前向声明,名称 f
将对编译器可见。
在第 9 行,声明了类型为 C
的名为 obj
的变量。 但是,此声明会引发错误,因为 C
只会在程序中的后期阶段声明,而不会前向声明。 若要修复该错误,可将 C
的整个定义移到 main
之前,或者为其添加前向声明。 此行为不同于 C# 等其他语言。 在这些语言中,函数和类可以在源文件中的声明位置之前使用。
在第 10 行,声明了类型为 std::string
的名为 str
的变量。 名称 std::string
可见,因为它是在 string
头文件中引入的,该文件已合并到第 1 行的源文件中。 std
是声明 string
类的命名空间。
在第 11 行,由于名称 j
尚未声明,因此会引发错误。 与 JavaScript 等其他语言不同,声明必须提供类型。 在第 12 行,使用了 auto
关键字,告知编译器根据用于初始化 k
的值来推理其类型。 在本例中,编译器选择 int
作为类型。
声明范围
声明引入的名称在出现声明的作用域内有效。 在以上示例中,在 main
函数内部声明的变量是局部变量。 可以在 main 外部的全局作用域内声明名为 i
的另一个变量,它将是一个单独的实体。 但是,这种名称重复可能导致编程器混淆和错误,应该避免。 在第 21 行,在命名空间 N
的作用域内声明了类 C
。 使用命名空间有助于避免名称冲突。 大多数 C++ 标准库名称都在 std
命名空间中声明。 有关作用域规则如何与声明交互的详细信息,请参阅作用域。
定义
必须定义并声明某些实体,包括函数、类、枚举和常量变量。 稍后在程序中使用实体时,定义将为编译器提供生成计算机代码所需的所有信息。 在以上示例中,第 3 行包含函数 f
的声明,但该函数的定义在第 15 到 18 行中提供。 在第 21 行,声明和定义了类 C
(不过,定义该类没有任何意义)。 必须在声明常量变量的同一语句中定义该变量,换言之,为其赋值。 内置类型(例如 int
)的声明将自动成为定义,因为编译器知道要为其分配多少空间。
以下示例演示的声明也是定义:
// Declare and define int variables i and j.
int i;
int j = 10;
// Declare enumeration suits.
enum suits { Spades = 1, Clubs, Hearts, Diamonds };
// Declare class CheckBox.
class CheckBox : public Control
{
public:
Boolean IsChecked();
virtual int ChangeState() = 0;
};
下面这些声明不是定义:
extern int i;
char *strchr( const char *Str, const char Target );
Typedef 和 using 语句
在早期版本的 C++ 中,typedef
关键字用于声明一个新名称,该名称是另一个名称的别名。 例如,类型 std::string
是 std::basic_string<char>
的另一个名称。 编程器使用 typedef 名称而不是实际名称的原因应该很明显。 新式 C++ 优先使用 using
关键字而不是 typedef
,但思路是相同的:为已声明并定义的实体声明一个新名称。
静态类成员
静态类数据成员是类的所有对象共享的离散变量。 由于它们是共享的,因此必须在类定义的外部定义和初始化。 有关详细信息,请参阅类。
外部声明
C++ 程序可能包含多个编译单元。 若要声明在单独的编译单元中定义的实体,请使用 extern
关键字。 声明中的信息对于编译器而言已足够。 但是,如果在链接步骤中找不到实体的定义,则链接器将引发错误。
本部分内容
存储类
const
constexpr
extern
初始值设定项
别名和 typedef
using
声明
volatile
decltype
C++ 中的特性