聲明某事與定義某事不同。有時候你可以同時做兩個事情,但是你需要同時聲明和定義一些事情。
爲什麼?
那麼,因爲標準這麼說,但標準爲什麼這麼說呢?
它與編譯和鏈接工作的方式有關。如果我有幾個源文件,a.cpp
和b.cpp
和幾個頭文件,a.h
和b.h
然後我想編譯它們。一般來說,您可以單獨編譯所有源文件以獲得a.o
和b.o
,然後將它們鏈接在一起以獲得最終的程序。
說我們有:
// a.h =========================
class A { static int n; };
// b.h =========================
class B { static int n; };
// a.cpp =======================
#include "a.h"
#include "b.h"
int foo() { return A::n + B::n; }
// b.cpp =======================
#include "a.h"
#include "b.h"
int bar() { return A::n - B::n; }
請記住,#include
基本上只是貼了包括文件中的其他文件。因此,所有的編譯器看到,當我們編譯a.cpp
和b.cpp
是:
// a.cpp =======================
class A { static int n; };
class B { static int n; };
int foo() { return A::n + B::n; }
// b.cpp =======================
class A { static int n; };
class B { static int n; };
int bar() { return A::n - B::n; }
哪個對象文件應該A::n
和B::n
進去? a.o
或b.o
?它在a.cpp
和b.cpp
中聲明,所以編譯器不知道該把它放在哪裏。如果你把它放在兩個地方,那麼你會定義它兩次,編譯器將不知道要使用哪個(在這種情況下,鏈接器會給你一個'多重定義的符號'錯誤)。
這就是爲什麼我們需要一個定義。該定義告訴我們哪個對象文件將其放入。
// a.cpp =======================
#include "a.h"
#include "b.h"
int A::n = 0; // A::n goes in a.o
int foo() { return A::n + B::n; }
// b.cpp =======================
#include "a.h"
#include "b.h"
int B::n = 0; // B::n goes in b.o
int bar() { return A::n - B::n; }
值得指出的是,你可以在b.cpp
已經把無論是在a.cpp
或兩者兼而有之。沒關係,只要定義一次。
因爲這就是語言所需。 –
[C++靜態成員變量及其初始化]的可能重複(http://stackoverflow.com/questions/4547660/c-static-member-variable-and-its-initialization) –