声明引入标识符并描述其类型,无论是类型,对象还是函数。声明是编译器接受对该标识符的引用所需的 。这些是声明:
extern int bar;
extern int g(int, int);
double f(int, double); // extern can be omitted for function declarations
class foo; // no extern allowed for type declarations
定义实际上实例化 / 实现此标识符。这是链接器将引用链接到这些实体所需的内容。这些是与上述声明相对应的定义:
int bar;
int g(int lhs, int rhs) {return lhs*rhs;}
double f(int i, double d) {return i+d;}
class foo {};
可以使用定义来代替声明。
可以根据需要随时声明标识符。因此,以下内容在 C 和 C ++ 中是合法的:
double f(int, double);
double f(int, double);
extern double f(int, double); // the same as the two above
extern double f(int, double);
但是,它必须只定义一次。如果您忘记定义已在某处声明和引用的内容,则链接器不知道链接引用的内容和抱怨缺少的符号。如果您多次定义某些内容,则链接器不知道将哪些定义链接引用并抱怨重复的符号。
由于辩论什么是 C ++ 中的类声明与类定义不断出现(对其他问题的答案和评论),我将在此处粘贴 C ++ 标准的引用。
在 3.1 / 2,C ++ 03 说:
声明是一个定义,除非它是一个类名声明 [...]。
3.1 / 3 然后举几个例子。其中包括:
[Example: [...] struct S { int a; int b; }; // defines S, S::a, and S::b [...] struct S; // declares S —end example
总结一下:C ++ 标准考虑了struct x;
成为声明和struct x {};
一个定义 。 (换句话说, “前向声明” 用词不当 ,因为 C ++ 中没有其他形式的类声明。)
感谢litb(Johannes Schaub)在他的一个答案中挖出了实际的章节和经文。
从 C ++ 标准 3.1 节:
声明将名称引入翻译单元或重新声明先前声明引入的名称。声明指定了这些名称的解释和属性。
下一段说明(强调我的)声明是一个定义,除非......
... 它声明了一个函数而没有指定函数的主体
void sqrt(double); // declares sqrt
... 它在类定义中声明了一个静态成员
struct X
{
int a; // defines a
static int b; // declares b
};
... 它声明了一个类名
class Y;
... 它包含没有初始值设定项或函数体的extern
关键字
extern const int i = 0; // defines i
extern int j; // declares j
extern "C"
{
void foo(); // declares foo
}
... 或者是typedef
或using
语句。
typedef long LONG_32; // declares LONG_32
using namespace std; // declares std
现在有一个重要原因,为什么理解声明和定义之间的区别很重要: 一个定义规则 。从 C ++ 标准的 3.2.1 节:
任何翻译单元都不得包含任何变量,函数,类类型,枚举类型或模板的多个定义。
声明:“某处,有一个 foo。”
定义:“...... 就在这里!”