const で定義された定数は、そのスコープを超えるとその空間は解放されますが、static で定義された静的定数は関数の実行後もその記憶領域は解放されません。

static は静的を意味します。クラスの静的メンバー関数、静的メンバー変数はクラスに関連しており、クラスの具体的なオブジェクトには関連していません。具体的なオブジェクトがなくても、クラスの静的メンバー関数とメンバー変数を呼び出すことができます。一般的に、クラスの静的関数はほぼグローバル関数ですが、そのスコープがそれを含むファイル内に限定されているだけです。

C++ では、static 静的メンバー変数はクラスの内部で初期化できません。クラスの内部では宣言のみであり、定義はクラス定義本体の外部で行う必要があります。通常はクラスの実装ファイルで初期化します。例:double Account::Rate = 2.25;

static キーワードはクラス定義体内部の宣言にのみ使用でき、定義時に static と指定することはできません。

C++ では、const メンバー変数もクラス定義の場所で初期化できず、コンストラクタの初期化リストによってのみ初期化でき、コンストラクタが必要です。

const データメンバーは、あるオブジェクトの生存期間内でのみ定数であり、クラス全体としては変更可能です。クラスは複数のオブジェクトを作成できるため、異なるオブジェクトの const データメンバーの値は異なる場合があります。そのため、クラスの宣言内で const データメンバーを初期化することはできません。クラスのオブジェクトが作成されていないとき、コンパイラは const データメンバーの値が何であるかを知らないからです。

const データメンバーの初期化は、クラスのコンストラクタの初期化リストでのみ行えます。クラス全体で一定の定数を確立したい場合は、クラス内の列挙型定数を使用するか、static const を使用して実現する必要があります。

class Test{ public: Test():a(0){} enum {size1=100,size2=200}; private: const int a;//コンストラクタの初期化リストでのみ初期化できる static int b;//クラスの実装ファイルで定義して初期化する conststatic int c;//static const int c; と同じ。 }; int Test::b=0;//staticメンバー変数は、特定のオブジェクトに属さないため、コンストラクタの初期化リストで初期化することはできません。 cosnt intTest::c=0;//注意:静的メンバー変数に値を代入するときは、static 修飾子を付ける必要はありませんが、const を付ける必要があります。

const メンバー関数の主な目的は、メンバー関数がオブジェクトの内容を変更するのを防ぐことです。つまり、const メンバー関数はメンバー変数の値を変更できませんが、メンバー変数にアクセスすることはできます。メンバー関数を const として宣言する場合、その関数は const メンバー関数でなければなりません。

static メンバー関数の主な目的は、クラススコープのグローバル関数として機能することです。クラスの非静的データメンバーにアクセスできません。クラスの静的メンバー関数には this ポインタがないため、次の結果が生じます:

  • 1. クラスの非静的メンバー変数に直接アクセスしたり、非静的メンバー関数を呼び出したりすることができません。
  • 2. virtual として宣言することができません。

static、const、static const、const static メンバーの初期化問題について

1. クラス内の const メンバーの初期化:

クラス内で const を設定する場合、それに初期値を与えることはできません。

class foo{ public: foo():i(100){} private: const int i=100;//error!!! }; //またはこのような方法で初期化を行う foo::foo():i(100){}

2. クラス内の static メンバーの初期化:

クラス内の static 変数はクラスに属し、特定のオブジェクトには属しません。プログラム全体の実行中にコピーは1つだけです。そのため、オブジェクトを定義するときに変数を初期化することはできません。つまり、コンストラクタで初期化することはできません。正しい初期化方法は次のとおりです:

データ型 クラス名::静的データメンバ名=値;
class foo{ public: foo(); private: staticint i; }; intfoo::i=20;

これは次のことを示しています:

  • 1. 初期化はクラス外で行い、先頭に static を付けません。通常の静的変数やオブジェクトと混同しないようにするためです。
  • 2. 初期化時には、そのメンバーのアクセス権限の制御指定子(private、public など)を付けません。
3. 初期化時にはスコープ演算子を使用して、それが所属するクラスを示します。したがって、静的データメンバーはクラスのメンバーであり、オブジェクトのメンバーではありません。

3. クラス内の static const と const static メンバーの初期化

この2つの書き方の効果は同じです。覚えやすいように、ここでは一般的な初期化方法を1つだけ説明します。

class Test{ public: static const int mask1; conststatic int mask2; }; constTest::mask1=0xffff; constTest::mask2=0xffff; //それらの初期化に違いはありません。一方は静的定数で、もう一方は定数静的ですが、どちらも静的であり、グローバル変数領域に格納されます。実際、最終結果は同じです。コンパイラによって処理が異なる場合もありますが、最終結果はすべて同じです。

完全な例

例

#ifdef A_H_ #define A_H_ #include <iostream> usingnamespace std; class A{ public: A(int a); staticvoid print();//静的メンバー関数 private: static int aa;//静的データメンバーの宣言 staticconst int count;//定数静的データメンバー(コンストラクタ内で初期化可能) const int bb;//定数データメンバー }; int A::aa=0;//静的メンバーの定義 + 初期化 const int A::count=25;//静的定数メンバーの定義 + 初期化 A::A(int a):bb(a){//定数メンバーの初期化 aa+=1; } void A::print(){ cout<<"count="<<count<<endl; cout<<"aa="<<aa<<endl; } #endif void main(){ A a(10); A::print();//クラスを介して静的メンバー関数にアクセスする a.print();//オブジェクトを介して静的メンバー関数にアクセスする }

初期化位置

静的メンバーはクラスの定義内で初期化できません(int を除く)。ヘッダーファイル内では初期化できません。

例えば、myclass.h を定義した場合、通常は myclass.cpp 内でそれを初期化します。


C++ クラスの静的メンバー(static)

静的メンバーが導入されたのは、データ共有の問題を解決するためです。共有を実現するには多くの方法があります。例えば、グローバルな変数やオブジェクトを設定する方法があります。しかし、グローバル変数やオブジェクトには限界があります。この章では、主にクラスの静的メンバーを使用してデータ共有を実現する方法について説明します。

静的データメンバー

クラス内では、静的メンバーによって複数のオブジェクト間でのデータ共有を実現でき、静的データメンバーを使用しても隠蔽の原則を破壊しません。つまり安全性が保証されます。したがって、静的メンバーはクラスのすべてのオブジェクト間で共有されるメンバーであり、特定のオブジェクトのメンバーではありません。

静的データメンバーを使用するとメモリを節約できます。すべてのオブジェクトに共通のものであるため、複数のオブジェクトに対して静的データメンバーは1か所にのみ格納され、すべてのオブジェクトで共用されます。静的データメンバーの値は各オブジェクトで同じですが、その値は更新できます。静的データメンバーの値を一度更新するだけで、すべてのオブジェクトが更新後の同じ値にアクセスすることが保証されるため、時間効率が向上します。

静的データメンバーの使用方法と注意事項は次のとおりです:

1. 静的データメンバーは、定義または説明の際に先頭にキーワード static を付けます。

2. 静的メンバーの初期化は、通常のデータメンバーの初期化とは異なります。静的データメンバーの初期化の形式は次のとおりです:

 
<データ型><クラス名>::<静的データメンバ名>=<値>

これは次のことを示しています:

  • (1) 初期化はクラス外で行い、先頭に static を付けません。通常の静的変数やオブジェクトと混同しないようにするためです。
  • (2) 初期化時には、そのメンバーのアクセス権限制御指定子(private、public など)を付けません。
  • (3) 初期化時にはスコープ演算子を使用して、それが所属するクラスを示します。したがって、静的データメンバーはクラスのメンバーであり、オブジェクトのメンバーではありません。

3. 静的データメンバーは静的記憶域を持ち、静的生存期間です。必ず初期化する必要があります。

4. 静的データメンバーを参照する場合、次の形式を使用します:

<クラス名>::<静的メンバ名>

静的データメンバーのアクセス権限が許可されていれば(つまり public メンバーの場合)、プログラム内で上記の形式に従って静的データメンバーを参照できます。

次に、静的データメンバーの応用を説明する例を示します:

例

#include … class Myclass{ public: Myclass(int a, int b, int c); void GetNumber(); void GetSum(); private: int A, B, C; static int Sum; }; int Myclass::Sum = 0; Myclass::Myclass(int a, int b, int c){ A = a; B = b; C = c; Sum += A+B+C; } void Myclass::GetNumber(){ cout<<"Number="<<a<<","<<b<<","<<c<<endl; } void Myclass::GetSum(){ cout<<"Sum="<<sum<<endl; } void main(){ Myclass M(3, 7, 10),N(14, 9, 11); M.GetNumber(); N.GetNumber(); M.GetSum(); N.GetSum(); }

出力結果から、Sum の値は M オブジェクトでも N オブジェクトでも等しいことがわかります。これは、M オブジェクトを初期化するときに、M オブジェクトの3つの int 型データメンバーの値の合計が Sum に代入され、Sum がその値を保存するためです。N オブジェクトを初期化するときに、N オブジェクトの3つの int 型データメンバーの値の合計が Sum の既存の値に加算され、Sum は更新後の値を保存します。したがって、オブジェクト M を介して参照しても、オブジェクト N を介して参照しても、値は同じ、つまり54になります。

静的メンバー関数

静的メンバー関数は静的データメンバーと同様に、どちらもクラスの静的メンバーに属し、どちらもオブジェクトのメンバーではありません。そのため、静的メンバーの参照にはオブジェクト名は必要ありません。

静的メンバー関数の実装では、クラス内で宣言された非静的メンバーを直接参照できませんが、クラス内で宣言された静的メンバーは参照できます。静的メンバー関数内で非静的メンバーを参照する必要がある場合は、オブジェクトを介して参照できます。以下に例を示して説明します。

例

#include … class M{ public: M(int a){ A=a; B+=a; } static void f1(M m); private: int A; static int B; }; void M::f1(M m) { cout<<"A="<<m.a<<endl; cout<<"B="<<b<<endl; } int M::B=0; void main() { M P(5),Q(10); M::f1(P); //呼び出し時にオブジェクト名は不要 M::f1(Q); }

読者は自分でその結果を分析できます。これからわかるように、静的メンバー関数の呼び出しには次の形式を使用します:

  
<クラス名>::<静的メンバ関数名>(<引数表>);

C++ における各種タイプのメンバー変数の初期化方法

C++ のさまざまなタイプのメンバーは、static であるかどうか、const であるかどうかによって、初期化方法が異なります。Java の構文はそれほど複雑ではないので、多くの人が Java を学びに行くのも無理はありません。以前、面接でこの問題を聞かれて答えられず、コードを書くときもよく混乱していました。ここでは本を調べてまとめます。

//-----------------Test.h---------------------------- #pragma once class Test { private : int var1; // int var11= 4; 誤った初期化方法 const int var2 ; // const int var22 =22222; 誤った初期化方法 static int var3; // static int var3333=33333; 誤り。静的定数intメンバーのみ直接代入で初期化できる static const int var4=4444; // 正しい。静的定数メンバーは直接初期化できる static const int var44; public: Test(void); ~Test(void); }; //--------------------Test.cpp----------------------------------- #include ".\test.h" int Test::var3 = 3333333; // 静的メンバーの正しい初期化方法 // int Test::var1 = 11111;; 誤り。静的メンバーのみ初期化できる // int Test::var2 = 22222; 誤り // int Test::var44 = 44444; // 誤った方法。再定義のエラーが出る Test::Test(void):var1(11111),var2(22222)正しい初期化方法//var3(33333)はここでは初期化できない { var1 =11111; //正しい。通常の変数もここで初期化できる //var2 = 222222; 誤り。定数は代入できないため、"constructor initializer(コンストラクタの初期化リスト)"でのみ初期化できる var3 =44444; //この代入は正しいが、すべてのオブジェクトで1つの静的メンバーを共有するため、他に影響を与える。これは初期化とは呼べないだろう } Test::~Test(void){} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

一部のメンバー変数のデータ型は特殊で、その初期化方法も通常のデータ型のメンバー変数とは異なります。これらの特殊な型のメンバー変数には次のものがあります:

  • a. 定数型メンバー変数
  • b. 参照型メンバー変数
  • c. 静的メンバー変数
  • d. 整数型の静的定数メンバー変数
  • e. 非整数型の静的定数メンバー変数

定数型メンバー変数と参照型メンバー変数の初期化は、コンストラクタの初期化リストによって行う必要があります。コンストラクタ本体で定数型メンバー変数や参照型メンバー変数に代入する方法は通用しません。

静的メンバー変数の初期化もかなり特別です。

以下のコードとその中のコメントを参照してください:

// Initialization of Special Data Member #include <iostream> using namespace std; class BClass { public: BClass() : i(1),ci(2), ri(i) // 定数型メンバー変数と参照型メンバー変数は、 { // パラメータ化リストによって初期化する必要があります。コンストラクタ本体で代入する方法は通用しません。 } voidprint_values() { cout<< "i =\t" << i << endl; cout<< "ci =\t" << ci << endl; cout<< "ri =\t" << ri << endl; cout<< "si =\t" << si << endl; cout<< "csi =\t" << csi << endl; cout<< "csi2 =\t" << csi2 << endl; cout<< "csd =\t" << csd << endl; } private: inti; // 通常のメンバー変数 constint ci; // 定数メンバー変数 int&ri; // 参照メンバー変数 staticint si; // 静的メンバー変数 //staticint si2 = 100; // error: 静的定数メンバー変数のみ、このように初期化できる staticconst int csi; // 静的定数メンバー変数 staticconst int csi2 = 100; // 静的定数メンバー変数の初期化(Integral type) (1) staticconst double csd; // 静的定数メンバー変数(non-Integral type) //staticconst double csd2 = 99.9; // error: 静的定数整数型データメンバーのみクラス内で初期化できる }; // 静的メンバー変数の初期化(Integral type) int BClass::si = 0; // 静的定数メンバー変数の初期化(Integral type) const int BClass::csi = 1; // 静的定数メンバー変数の初期化(non-Integral type) const double BClass::csd = 99.9; // (1)のcsi2の初期化では、Stanley B. Lippmanによれば次の行が必要です。 // ただしVC2003では次の行があるとエラーになりますが、VC2005では次の行はあってもなくてもよく、コンパイラに依存します。 const int BClass::csi2; int main(void) { BClassb_class; b_class.print_values(); return0; }

C++ 静的メンバーまとめ、C++、static

クラスの静的メンバーは本当に愛憎相半ばする特性です。かつて面接で、面接官にこの問題を徹底的に追及され、顔を真っ赤にして敗北したことがあります。それで帰って

から、悔しさを胸に刻み、静的クラスメンバーの知識ポイントをしっかりまとめて、今後の面接でこの種の問題に受動的にならないようにしようと決めました。

静的クラスメンバーは、静的データメンバーと静的関数メンバーの2つの部分から構成されます。

静的データメンバー

クラス本体のデータメンバーの宣言の前にstaticキーワードを付けると、そのデータメンバーはそのクラスの静的データメンバーになります。他のデータメンバーと同様に、静的データメンバーもpublic/protected/privateのアクセス規則に従います。また、静的データメンバーには以下の特徴があります:

1. 静的データメンバーの定義。

静的データメンバーは実際にはクラススコープ内のグローバル変数です。したがって、静的データメンバーの定義(初期化)はヘッダーファイルに置くべきではありません。(宣言 vs. 定義(初期化))その定義方法はグローバル変数と同じです。例は以下の通りです:

xxx.hファイルclass base{ private: static const int _i;//宣言。標準C++はクラス本体内での順序型の初期化をサポートするが、VC6はサポートしていない。 }; xxx.cppファイルconst int base::_i=10;//定義(初期化)時はprivateおよびprotectedのアクセス制限を受けない。

注:ヘッダーファイルで静的データメンバーを定義(初期化)しようとしないでください。ほとんどの場合、これを行うと再定義エラーが発生します。たとえ#ifndef #define #endifまたは#pragma onceを付けてもダメです。

2. 静的データメンバーはクラスのすべてのオブジェクトによって共有されます。これにはそのクラスの派生クラスのオブジェクトも含まれます。つまり、派生クラスのオブジェクトは基底クラスのオブジェクトと基底クラスの静的データメンバーを共有します。例は以下の通りです:

class base{ public : static int _num;//宣言 }; int base::_num=0;//静的データメンバーの実際の定義 class derived:public base{ }; main() { base a; derived b; a._num++; cout<<"base class static data number_num is"<<a._num<<endl; b._num++; cout<<"derived class static datanumber _num is"<<b._num<<endl; } // 結果は1,2。派生クラスと基底クラスが1つの静的データメンバーを共用していることがわかる。

3. 静的データメンバーはメンバー関数のデフォルト引数にできますが、通常のデータメンバーはできません。例は以下の通りです:

class base{ public : static int _staticVar; int _var; void foo1(int i=_staticVar);//正しい。_staticVarは静的データメンバー void foo2(int i=_var);//誤り。_varは通常のデータメンバー };

4. 静的データメンバーの型は所属クラスの型にできますが、通常のデータメンバーはできません。通常のデータメンバーは所属クラス型のポインタまたは参照としてのみ宣言できます。例は以下の通りです:

class base{ public : static base_object1;//正しい。静的データメンバー base _object2;//誤り base *pObject;//正しい。ポインタ base &mObject;//正しい。参照 };

5. この特性が標準C++のものなのか、VC6独自のものなのかはわかりません。

静的データメンバーの値はconstメンバー関数内で合法的に変更できます。例は以下の通りです:

class base{ public: base(){ _i=0; _val=0; } mutable int _i; static int _staticVal; int _val; void test() const{//constメンバー関数 _i++;//正しい。mutableデータメンバー _staticVal++;//正しい。staticデータメンバー _val++;//誤り } }; int base::_staticVal=0;

静的メンバー関数

静的メンバー関数にはそれほど多くの説明事項はありません。

1. 静的メンバー関数のアドレスは通常の関数ポインタに格納できますが、通常のメンバー関数のアドレスはクラスメンバー関数ポインタに格納する必要があります。例は以下の通りです:

class base{ static int func1(); int func2(); }; int (*pf1)()=&base::func1;//通常の関数ポインタ int (base::*pf2)()=&base::func2;//メンバー関数ポインタ

2. 静的メンバー関数はクラスの非静的メンバーを呼び出すことはできません。静的メンバー関数はthisポインタを持たないためです。

3. 静的メンバー関数はvirtual、const、volatile関数として同時に宣言することはできません。例は以下の通りです:

class base{ virtual static void func1();//誤り static void func2() const;//誤り static void func3() volatile;//誤り };

最後に一点、静的メンバーは独立してアクセスできます。つまり、オブジェクトインスタンスを一切作成しなくてもアクセスできます。

作者:SDMrFeng

原文:https://blog.csdn.net/tobefxz/article/details/14109697