静的メンバ(C++)
キーワード this への移動
記憶クラス指定子 static(C++) は、クラス宣言のデータや関数のメンバに指定できます。指定されたメンバは静的メンバと呼ばれ、非静的メンバとは異なる特性を持ちます。非静的メンバの場合には、クラスのインスタンスごとに別個のコピーが存在します。それに対して静的メンバの場合は、コピーは 1 つしか存在せず、クラスの具体的なオブジェクトを参照せずにそのメンバにアクセスできます。x がクラス X の静的メンバであるとすると、x は X::x として参照できます(クラス X のオブジェクトがまだ作成されていなくても構いません)。通常のメンバ アクセス演算子を使って x にアクセスすることも可能です。たとえば、y がクラス X のオブジェクトであり、yptr がクラス X のオブジェクトを指すポインタだとすると、y.x や yptr->x のようにしてアクセスできます(ただし、y および yptr という式は評価されません)。特に、静的メンバ関数は、特別なメンバ関数構文を使っても使わなくても呼び出すことができます。
class X { int member_int; public: static void func(int i, X* ptr); }; void g(void) { X obj; func(1, &obj); // error unless there is a global func() // defined elsewhere X::func(1, &obj); // calls the static func() in X // OK for static functions only obj.func(1, &obj); // so does this (OK for static and // nonstatic functions) }
静的メンバ関数は、特定のオブジェクトを想定せずに呼び出せるため、this ポインタを持ちません。そのため、. または -> を使って明示的にオブジェクトを指定しなければ、非静的メンバにアクセスすることができません。たとえば、先ほどの例の宣言に含まれる func の定義を考えてみます。
void X::func(int i, X* ptr) { member_int = i; // which object does member_int // refer to? Error ptr->member_int = i; // OK: now we know! }
インライン関数を除いて、グローバル クラスの静的メンバ関数は外部結合を持ちます。静的メンバ関数は仮想関数にすることができません。名前と引数の型が同じである静的メンバ関数と非静的メンバ関数を持つことはできません。
クラス宣言内での静的データ メンバの宣言は定義ではないため、他で定義して記憶領域を割り当て、初期化する必要があります。
何らかの関数のローカルで宣言されたクラスの静的メンバは、結合を持たず、初期化できません。グローバル クラスの静的メンバは、ファイル スコープの中であれば、通常のグローバル オブジェクトと同様に初期化できます。ネストされているレベルに関係なく、静的メンバには、初期化できることを除いて、通常のクラス メンバのアクセス規則が適用されます。
class X { static int x; static const int size = 5; class inner { static float f; void func(void); // nested declaration }; public : char array[size]; }; int X::x = 1; float X::inner::f = 3.14; // initialization of nested static void X::inner::func(void) { /* define the nested function */ }
静的メンバの主な用途は、そのクラスのすべてのオブジェクトに共通するデータ(たとえば、作成されたオブジェクトの数や、すべてのオブジェクトが共有するプールで最後に使われたリソースなど)を管理することです。その他に、静的メンバは以下の用途にも使われます。
- 外から見えるグローバルな名前の数を減らす
- どの静的オブジェクトが論理的にどのクラスに属しているかを明らかにする
- 静的メンバ名に対するアクセス制御を可能にする