クラス及び構造体の静的メンパ

静的メンパ

クラスのメンバは、ストレージクラス修飾子 static を使用して宣言することが出来ます。これらのデータメンバはクラスの全てのインスタンスで共有されて 1 つの場所に格納されます。非静的データメンバは、各クラスのオブジェクト変数のために作成されます。

クラスの静的メンバを宣言することが出来なければこれらのデータをプログラムのグローバルレベルで宣言することが必要になります。これはデータとクラス間の関係を破り、クラスでデータとそれらを処理するためのメソッドを結合するという OOP の基本的なパラダイムと一致しないでしょう。静的メンバは特定のインスタンスに固有でないクラスのデータがクラススコープ内に存在することを可能にします。

静的クラスメンバは特定のインスタンスに依存しないため、それへの参照は次のようになされます。

class_name::variable

ここで class_name がクラス名で variable がクラスメンバ—名です。

ご覧のように、クラスの静的メンバにアクセスするにはコンテキスト解決演算子 ::が使用されます。クラスのメソッド内で静的メンバにアクセスする際にはコンテキスト演算子は任意です。

クラスの静的メンバは、明示的に所望の値で初期化する必要があります。このためには、クラスの静的メンバはグローバルスコープで初期化また宣言されなければなりません。静的メンバの初期化の順序は、そのグローバルスコープでの宣言の順序に対応します。

例えば、テキスト解析クラス CParser があって、処理された単語や文字の合計数を数える必要があるとします。必要なクラスのメンバのみを static として宣言し、それらをグローバルレベルで初期化する必要があります。クラスの全てのインスタンスは、単語や文字の共通のカウンタを使用します。

//+------------------------------------------------------------------+
//| テキスト解析クラス                                                     |
//+------------------------------------------------------------------+
class CParser
 {
public:
  static int        s_words;
  static int        s_symbols;
  //--- コンストラクタとデストラクタ
                    CParser(void);
                   ~CParser(void){};
 };
...
//--- グローバルレベルでの Parser クラスの静的メンバの初期化
int CParser::s_words=0;
int CParser::s_symbols=0;

静的クラスメンバは const キーワードを使用して宣言されます。静的定数はグローバルレベルで const キーワードを使用して初期化されます。

//+------------------------------------------------------------------+
//| 処理されたデータを格納するためのスタッククラス                                  |
//+------------------------------------------------------------------+
class CStack
 {
public:
                    CStack(void);
                   ~CStack(void){};
...
private:
  static const int  s_max_length; // スタックの最大許容
 };
 
//--- CStack クラスの静的定数の初期化
const int CStack::s_max_length=1000;

this ポインタ #

キーワード this はそれ自体(つまり、メソッドが実行されたコンテキスト内の特定のクラスインスタンス)に暗黙的に宣言されたポインタを示します。これは、クラスの非静的メソッド内のみで使用することが出来ます。this ポインタはクラスの暗黙的な非静的メンバです。

静的関数では、クラスの静的メンバと静的メソッドのみにアクセスすることが出来ます。

静的メソッド

MQL5 では static 型のメンバ関数が使用出来ます。static 修飾子は、クラス内の宣言では関数の戻り値の型を先行しなければなりません。

class CStack
 {
public:
  //--- コンストラクタとデストラクタ
                    CStack(void){};
                   ~CStack(void){};
  //--- 最大スタック容量
  static int        Capacity();
private:
  int               m_length;     // スタック内の要素数
  static const int  s_max_length; // スタックの最大許容
 };
//+------------------------------------------------------------------+
//| スタックに格納出来る要素の最大数を返す                                     |
//+------------------------------------------------------------------+
int CStack::Capacity(void)
 {
  return(s_max_length);
 }
//--- CStack クラスの静的定数の初期化
const int CStack::s_max_length=1000;
//+------------------------------------------------------------------+
//| スクリプトプログラムを開始する関数                                          |
//+------------------------------------------------------------------+
void OnStart()
 {
//--- 型の変数を宣言
  CStack stack;
//--- オブジェクトの静的メソッドを呼び出す
  Print("CStack.s_max_length=",stack.Capacity());
//--- メソッドが静的でありオブジェクトの存在を必要としないため次のような呼び出しも可能
  Print("CStack.s_max_length=",CStack::Capacity());
 }

const 修飾子を持つメソッドは定数と呼ばれ、そのクラスの暗黙のメンバを変更することは出来ません。クラスの定数関数と定数パラメータの宣言は定数コレクトネス制御と呼ばれます。この制御により、コンパイラがオブジェクトの値の一貫性を確保し、問題がある場合にはコンパイル時にエラーを返すことを確認出来ます。

const 修飾子はクラス宣言内で引数リストの後に配置されます。クラス外での定義も const 修飾子を含む必要があります。

//+------------------------------------------------------------------+
//| 四角形クラス                                                         |
//+------------------------------------------------------------------+
class CRectangle
 {
private:
  double            m_width;     // 幅 
  double            m_height;     // 高さ
public:
  //--- コンストラクタとデストラクタ
                    CRectangle(void):m_width(0),m_height(0){};
                    CRectangle(const double w,const double h):m_width(w),m_height(h){};
                   ~CRectangle(void){};
  //--- 面積の計算
  double            Square(void) const;
  static double     Square(const double w,const double h);// { return(w*h); }
 };
//+------------------------------------------------------------------+
//| 四角形オブジェクトの面積を返す                                           |
//+------------------------------------------------------------------+
double CRectangle::Square(void) const
 {
  return(Square(m_width,m_height));
 }
//+------------------------------------------------------------------+
//| 2 つの変数の積を返す                                                  |
//+------------------------------------------------------------------+
static double CRectangle::Square(const double w,const double h)
 {
  return(w*h);
 }
//+------------------------------------------------------------------+
//| スクリプトプログラムを開始する関数                                          |
//+------------------------------------------------------------------+
void OnStart()
 {
//--- 側面が 5 と 6 の四角形 rect を作成する
  CRectangle rect(5,6);
//--- 定数メソッドを使用して四角形の面積を求める
  PrintFormat("rect.Square()=%.2f",rect.Square());
//--- クラス CRectangle の静的メソッドを使用して数値の積を求める
  PrintFormat("CRectangle::Square(2.0,1.5)=%f",CRectangle::Square(2.0,1.5));
 }

定数制御を使用するもう 1 つの利点は、コンパイラが、定数オブジェクトを読み出し専用メモリに配置するなどの特別な最適化を適応することです。

const 修飾子は関数を呼び出す時にインスタンスメンバの不変を保証するため、静的な関数には const は使用できません。しかし、前述したように、静的関数は非静的クラスメンバにアクセスすることは出来ません。

参照

静的変数変数参照修飾子「 & 」とキーワード「 this 」