Объявление чего-то не совпадает с определением. Иногда вы можете делать оба одновременно, но в любом случае вам нужно как объявить, так и определить что-то.
Почему?
Хорошо, потому что стандарт говорит так, но почему стандарт так говорит?
Это связано с тем, как работают компиляция и компоновка. Если у меня есть несколько исходных файлов, 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; }
Стоит отметить, что вы могли бы положить как в a.cpp
или как в b.cpp
. Это не имеет значения, если он определен точно один раз.
Потому что это то, чего хочет язык. –
возможный дубликат [статической членной переменной C++ и ее инициализацией] (http://stackoverflow.com/questions/4547660/c-static-member-variable-and-its-initialization) –