class X {
static int i;
// some other function, variable declaration, cons, dest
};
int X :: i ; **(!)**
なぜ私はいつもその(!)行を書かなければならないのですか?
記述しないと、コンパイラーは内部リンケージを完了できないため、リンカーエラーが発生します(私は推測します)。なんで ?
それが静的メンバーの仕組みだからです。それらは、クラス内のインスタンスとは別に存在します。
クラス内でそれらを定義することはできません。その場合、クラスを使用しているすべての実装ファイルに対して複数の定義が存在するためです。
したがって、静的メンバーを実際に定義する実装ファイルを1つ選択する必要があります。
これは、単一定義規則として知られています。各グローバルオブジェクト(技術的には、外部リンケージを持つ各オブジェクト)は、正確に1つのソースファイル(技術的には、1つの変換単位)で定義する必要があります。ただし、何度でも宣言できます。
通常、クラス定義はヘッダーファイルに含まれ、多くのソースファイルに含まれている場合があります。したがって、静的メンバーをそこで定義することはできず、宣言するだけです。そうしないと、複数の定義が存在します。リンカが正確に1つの定義を見つけるには、静的メンバーを正確に1つのソースファイルで個別に定義する必要があります。それがマークされた行が(!)
行うことです。
静的変数は、TU(つまり、cppファイル)で(宣言されているのではなく)定義されている必要があります。
宣言されただけで定義されていない場合、ストレージは割り当てられないため、リンカはそれを見つけることができません。
static int i;
は宣言です。つまり、ある変換単位(=>.cpp
ファイル)でそのような静的フィールドが実際に定義されることをコンパイラーに通知します。そのような変数が存在することをコンパイラーに知らせ、それが宣言されている各変換単位でそれを使用できるようにする必要があります。
int X :: i;
代わりに、は定義であり、コンパイラにその変数のスペースを実際に提供するように指示します。それは単一にとどまらなければなりません.cpp
、さもなければ、各翻訳ユニットはそれ自身のためにそれのためにいくらかのスペースを提供するでしょう(そしてリンカーは文句を言うでしょう)。
extern
グローバルの場合、それを使用する必要のあるすべてのファイル(通常はヘッダーに配置)で宣言が必要であり、それを定義するシングルで通常の定義が必要なのとまったく同じ理由です.cpp
。
C ++は、宣言と定義を明確に区別します。コンパイラに2つのことを伝える必要があります。
これは通常、1つのステップ、つまりローカルint変数で実行されます。
void f() {
int x; // Declaration and definition.
}
.hppヘッダーファイルは多くの.cppファイルにインクルードできるため、(!)
行は単一の特定の.cppに存在する必要があり、通常はヘッダーファイルの外側にあります。
静的クラスメンバーはすべてのクラスインスタンス間で共有されるため(メモリ内にそのような変数が存在する唯一の場所があります)、したがってstatic int i;
クラス内宣言は変数宣言のみを表します-そしてその変数にメモリをどこかに割り当てる必要があります-それを定義する必要があります-これは、実装ファイルで行われます。int X::i;
クラス定義はメンバーのみを定義しますが、単一のコンパイル単位(つまり、.cppファイル)に存在する必要があります。
これは「単一定義規則」の一部であると言えます。