6

クラス宣言内で初期化できるのは、static、const、およびint / enum(c ++ 11より前)のデータメンバーのみであることを理解しています。「他のすべての静的データメンバーは、グローバル名前空間スコープで(つまり、クラス定義の本体の外で)定義する必要があり、それらの定義でのみ初期化できます」。

クラス定義で他の静的データメンバーを初期化できないのはなぜですか?これが禁止された特別な理由はありましたか?

データメンバーがクラスに固有である場合、クラスに関連するスコープではなく、グローバル名前空間スコープで宣言されるのはなぜですか?

4

5 に答える 5

5

クラス定義で他の静的データメンバーを初期化できないのはなぜですか? これが禁止された特定の理由はありましたか?

おそらく、C++ には別の翻訳単位があるためです。コンパイラは、これらのシンボルの初期化ロジックが配置されるオブジェクト ファイルを選択する必要があります。これを特定のソース ファイルに強制すると、コンパイラはその決定を簡単に行うことができます。

データ メンバーがクラスに固有である場合、それらのクラスに関連するスコープではなく、グローバル名前空間スコープで宣言されているのはなぜですか?

それはまさに C++ がクラス メンバーを行う方法だからです。これは、メンバー関数などの他のクラス メンバーと同じです。

ヘッダー ファイル:

namespace example {

// Class declared in header
struct some_class
{
    // Member variable
    static float example;
    // Member function
    void DoStuff() const;
};

}

ソースファイル:

namespace example {

    // Implement member variable
    float some_class::example = 3.14159;
    // Implement member function
    void some_class::DoStuff() const
    {
         //....
    }
}

静的な const 整数メンバーをヘッダーで初期化できるようにする特定の例外があります。これにより、コンパイラーはそれらをコンパイル時の定数として扱うことができるようになります。つまり、それらを使用して、クラス定義で配列のサイズまたは他の同様のビットを定義できます。

于 2013-03-01T21:42:47.300 に答える
4

クラス定義で他の静的データメンバーを初期化できないのはなぜですか? これが禁止された特定の理由はありましたか?

一般に、すべての静的オブジェクトは、明確に定義されたアドレスを持つように、1 つの変換単位で定義する必要があります。特別な例外として、静的、定数、不揮発性クラス メンバーは、アドレスが必要ない場合は定義を必要とせず値をコンパイル時の定数で置き換えることができる十分に単純な型を持っています。

歴史的に、「十分に単純」は整数型または列挙型として定義されていました。C++11 はそれを拡張して、constexpr指定子を持つ任意のリテラル型を含めます。

データ メンバーがクラスに固有である場合、それらのクラスに関連するスコープではなく、グローバル名前空間スコープで宣言されているのはなぜですか?

グローバル名前空間スコープでは宣言されていません。それらはクラス内で宣言され、スコープが設定されます。

つまり、なぜそれらがクラス定義の外で定義されているのかというと、それは、プログラム全体で static メンバーの定義が 1 つだけでなければならないためです。ただし、クラスは、それを使用する各翻訳単位で定義する必要があります。

于 2013-03-01T21:58:04.050 に答える
2

クラス定義で他の静的データメンバーを初期化できないのはなぜですか? これが禁止された特定の理由はありましたか?

静的データ メンバーは、多くの点で (特にコンパイラの観点から)、外部リンケージを持つ名前空間スコープのデータ オブジェクトに似ています。

静的データ メンバーの宣言は単なる宣言であり、定義ではありません。これは、グローバル オブジェクトの宣言に似ておりextern、オブジェクトを使用できる翻訳単位に含める必要があります。

定義は正確に 1 つの翻訳単位に出現する必要があり、これは初期化式が属する場所です。式が定数式の厳密な基準を満たさない限り、その値はそれが呼び出された時間とコンテキストに大きく依存する可能性があります。このような初期化子式が複数の翻訳単位で発生すると、実行コンテキストと初期化の時間、そして最終的に初期値があいまいになります。

クラス スコープのコンパイル時定数は、特定の種類の定数静的メンバーの例外を作成するのに十分価値があると見なされました (列挙型の初期化や配列の次元の指定などに使用できます)。定数式を使用すると、異なる翻訳単位で異なる初期化子の値を誤って発生させることは、少なくともより困難です。constexprこの概念は、メンバーを使用して C++11 で拡張されました。

データ メンバーがクラスに固有である場合、それらのクラスに関連するスコープではなく、グローバル名前空間スコープで宣言されているのはなぜですか?

宣言はクラス スコープ内にあります。非定義宣言は文字どおりクラス定義内にあり、クラス メンバーの他のクラス外定義と同様に、定義は名前空間スコープに表示されます。メンバー名はクラス名で修飾されているため、クラスのメンバーとして明確に示され、初期化式は実際にはクラスのスコープ内にあると見なされます (少なくとも C++11 では、私は C+ を持っていません)。 +98/03 標準はこちらから入手できます)。

于 2013-03-01T22:03:34.217 に答える
1

あなたはそれを逆に見なければなりません。基本的に、静的データ メンバーは、ソース ファイル内のクラス定義の外で定義および初期化する必要があります。static const intメンバー配列のサイズを定義するためのさまざまな醜い回避策を回避するため、例外があります。

于 2013-03-01T23:17:30.497 に答える
-1

クラスがインスタンス化されるたびに、それらは再初期化されます。Foo 型の新しいオブジェクトを作成するたびに、すべての Foo の静的変数が初期値にリセットされますが、これはおそらくあなたが望むものではありません。したがって、オブジェクトで静的変数を使用する場合は、a) 値を変更できないため、同じ値に再初期化しても安全であるか、b) 初期化関数のコンテキスト外でのみ変更できます。

于 2013-03-01T21:46:55.600 に答える