トップ  >  リファレンス  >  基本  >  データ型  > クラス[class]
スポンサーリンク
検索
カスタム検索
リファレンスツリー
オススメ

天才数学者のエドワード・オークリー・ソープの物語とジョン・ケリーの公式は必見です。
クラス[class]



クラス

構造体[struct]との違いは以下の通りです:

・キーワードクラス(publicやprivate等)は宣言の中で使用します。
・全クラスのメンバーは指定しない限りデフォルトでアクセス指定子privateを持っています。
・クラスオブジェクトは常に仮想関数テーブルを持っています。
new演算子はクラスオブジェクトに適用します。
・クラスはクラスからのみ継承する事が出来ます。


クラスと構造体は明示的にコンストラクタとデストラクタを持つ事が出来ます。
明示的にコンストラクタ定義している場合、初期化シーケンスで構造体やクラス変数を初期化する事は出来ません。

サンプルソース:
struct trade_settings {
   double limit;        // リミット
   double stop;         // ストップロス
   uchar  slippage;     // スリップページ

   // コンストラクタ
   trade_settings() { 
                      take    = 0.0;
                      stop    = 0.0;
                      slippage= 5;
   }

   // デストラクタ
   ~trade_settings();
};

// 初期化シーケンス
trade_settings my_set={ 0.0, 0.0, 5};  // 初期化不可の為コンパイラエラーになります






コンストラクタ/デストラクタ


コンストラクタは、構造体またはクラスオブジェクトを作成する時に自動的に呼び出され、 通常はクラスメンバを初期化する為に使用します。


コンストラクタの名称は、クラス名と一致する必要があります。
コンストラクタには戻り値の型はありません(void型指定する事が出来ます)。

定義されたクラスメンバで初期化を必要とするオブジェクト(文字列、動的配列は、コンストラクタの有無に関係なく初期化されます。

各クラスは、パラメータの数や初期化リストによる違いから複数のコンストラクタを持つ事が出来ます。
パラメータ指定が必要なコンストラクタは、パラメトリックコンストラクタと呼ばれます。

パラメータ無しのコンストラクタは、デフォルトコンストラクタと呼ばれます。



クラス内でコンストラクタ宣言されていない場合は、コンパイラはコンパイル時にデフォルトコンストラクタを作成します。

サンプルソース:
class MyDateClass {
private:
   int m_year;  
   int m_month; 
   int m_day;   
   int m_hour;  
   int m_minute;
   int m_second;

public:
   // デフォルトコンストラクタ
   MyDateClass(void);

   // パラメトリックコンストラクタ
   MyDateClass(int h, int m, int s);
};




コンストラクタはクラスの記述の中で宣言する事ができ、そのbodyを定義する事が出来ます。
例えばMyDateClassの2つのコンストラクタは次のように定義する事が出来ます。
サンプルソース:
//+------------------------------------------------------------------+
//| デフォルトコンストラクタ                                              
//+------------------------------------------------------------------+
MyDateClass::MyDateClass(void) {

   MqlDateTime mdt;
   datetime t= TimeCurrent(mdt);
   m_year    = mdt.year;
   m_month   = mdt.mon;
   m_day     = mdt.day;

   m_hour    = mdt.hour;
   m_minute  = mdt.min;
   m_second  = mdt.sec;
   Print(__FUNCTION__);
}

//+------------------------------------------------------------------+
//| パラメトリックコンストラクタ                                     
//+------------------------------------------------------------------+
MyDateClass::MyDateClass(int h,int m,int s) {

   MqlDateTime mdt;
   datetime t= TimeCurrent(mdt);
   m_year    = mdt.year;
   m_month   = mdt.mon;
   m_day     = mdt.day;

   m_hour    = h;
   m_minute  = m;
   m_second  = s;
   Print(__FUNCTION__);
}


デフォルトコンストラクタにおいて、クラスの全てのメンバがTimeCurrent()関数の値が代入されます。
パラメトリックコンストラクタにおいては、時間の値(m_hour,m_minute,m_second)が入力され、他メンバ(m_year,m_month,m_day)は自動的に現在の日付で初期化されます。


デフォルトコンストラクタは、クラスオブジェクト配列を初期化する時に特別な用途を持っています。
パラメータがデフォルト値を持っているコンストラクタは、デフォルトコンストラクタではありません

サンプルソース:
//+------------------------------------------------------------------+
//| デフォルトコンストラクタを持つクラス 
//+------------------------------------------------------------------+
class CFoo {
   datetime          m_call_time;     // 最後にオブジェクトを呼び出した時の時間

public:
   // デフォルト値を持っているパラメータ。デフォルトコンストラクタではありません。
   CFoo(const datetime t=0){
       m_call_time = t;
   };
   // コピーコンストラクタ
   CFoo(const CFoo &foo){
       m_call_time = foo.m_call_time;
   };
 
   string ToString(){
    return(TimeToString(m_call_time,TIME_DATE|TIME_SECONDS));
   };
};

//+------------------------------------------------------------------+
//| スクリプトプログラム                                    
//+------------------------------------------------------------------+
void OnStart() {

// このバリアントは使用出来ません、デフォルトコンストラクタが設定されていません。
// CFoo foo; 


// 作成可能なクラスオブジェクト
   CFoo foo1(TimeCurrent());   // 明示的なパラメトリックコンストラクタ呼び出し
   CFoo foo2();                  // 明示的なパラメトリックコンストラクタ呼び出し(デフォルトパラメータ)
   CFoo foo3 = D'2009.09.09';    // 暗黙的なパラメトリックコンストラクタ呼び出し
   CFoo foo40(foo1);             // 明示的なコピーコンストラクタ呼び出し
   CFoo foo41 = foo1;            // 暗黙的なコピーコンストラクタ呼び出し
   CFoo foo5;                    // 明示的なデフォルトコンストラクタ呼び出し
                                 //(デフォルトコンストラクタで無い場合、デフォルト値を持つパラメトリックコンストラクタ呼び出しになります)

// 受信可能なオブジェクトポインタ
   CFoo *pfoo6 = new CFoo();                // 動的オブジェクトを作成し、そのポインタを受け取ります
   CFoo *pfoo7 = new CFoo(TimeCurrent()); // 動的オブジェクト作成(デフォルト以外のパラメータ)
   CFoo *pfoo8 = GetPointer(foo1);        // pfoo8にfoo1のオブジェクトポインタを設定
   CFoo *pfoo9 = pfoo7;                     // pfoo9にpfoo7のオブジェクトポインタを設定
   // CFoo foo_array[3];                    // これは使用出来ません。デフォルトコンストラクタは指定されていません。

// m_call_timeの値を表示
   Print("foo1.m_call_time  =",foo1.ToString() );
   Print("foo2.m_call_time  =",foo2.ToString() );
   Print("foo3.m_call_time  =",foo3.ToString() );
   Print("foo40.m_call_time =",foo40.ToString());
   Print("foo5.m_call_time  =",foo5.ToString() );
   Print("pfoo6.m_call_time =",pfoo6.ToString());
   Print("pfoo7.m_call_time =",pfoo7.ToString());
   Print("pfoo8.m_call_time =",pfoo8.ToString());
   Print("pfoo9.m_call_time =",pfoo9.ToString());

// 動的オブジェクトの削除
   delete pfoo6;
   delete pfoo7;
   //delete pfoo8;  // pfoo8を明示的に削除する必要はありません。
   //delete pfoo9;  // pfoo9を明示的に削除する必要はありません。
}



ユーザー定義のコンストラクタを持つクラスの場合、デフォルトコンストラクタはコンパイラによって生成されません。
これはパラメトリックコンストラクタはクラス内で宣言されている場合を意味します、しかしデフォルトコンストラクタは宣言されていません。
このクラスのクラスオブジェクト配列を宣言する事は出来ません(コンパイラがエラーを返します)。

サンプルソース:
//+------------------------------------------------------------------+
//| デフォルトコンストラクタ無しのクラス                              
//+------------------------------------------------------------------+
class CFoo {

   string            m_name;

public:
   CFoo(string name) { m_name=name;}
};

//+------------------------------------------------------------------+
//| Script program start function                                    
//+------------------------------------------------------------------+
void OnStart() {

   CFoo badFoo[5];      // コンパイル時にエラーになります。

}


この例ではCFooクラスは宣言されたパラメトリックコンストラクタを持ちます。
このような場合、コンパイラはコンパイル時に自動的にデフォルトコンストラクタを作成しません。
同時にオブジェクト配列を宣言する時、全てのオブジェクトが作成され自動的に初期化されている事が想定されます。

オブジェクトの自動初期化中は、デフォルトコンストラクタを呼び出す必要があります。
しかしデフォルトコンストラクタを明示的に宣言していないと自動的にコンパイラによって生成されない為、オブジェクト生成する事が出来ません。
その為、コンパイラはコンパイル時にエラーを返します。

コンストラクタを使用してオブジェクトを初期化する為の特別な構文があります。
構造体やクラスメンバのコンストラクタ初期化子(初期化の為の特別な構造)は、初期化リストで指定する事が出来ます。

初期化リストはカンマ(,)で区切られた初期化子のリストで、これはコンストラクタのパラメータリストの後のコロン(:)の後に来ます。
そしてbodyの前(中括弧の前)に来ます。

初期化リストにはいくつか要件があります。
・初期化リストはコンストラクタ内でのみ使用できます。
・親メンバは初期化リストで初期化する事は出来ません
・初期化リストは関数の定義(実装)によって続かなければなりません

サンプルソース:
//+------------------------------------------------------------------+
//| キャラクター名を格納する為のクラス                        
//+------------------------------------------------------------------+
class CPerson {
   string            m_first_name;     // ファーストネーム
   string            m_second_name;    // セカンドネーム

public:
   // 空のデフォルトコンストラクタ
   CPerson() {Print(__FUNCTION__);};

   // パラメトリックコンストラクタ
   CPerson(string full_name);

   // 初期化リストを持つコンストラクタ
   CPerson(string surname, string name): m_second_name(surname), m_first_name(name) {};

   void PrintName(){
                    PrintFormat("Name=%s Surname=%s",m_first_name,m_second_name);
                   };
};

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CPerson::CPerson(string full_name) {

   int pos=StringFind(full_name," ");

   if( pos >= 0 ) {
      m_first_name =StringSubstr(full_name,0,pos);
      m_second_name=StringSubstr(full_name,pos+1);
   }
}

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart() {

   // 「デフォルトコンストラクタが定義されていません」というエラーが発生します
   CPerson people[5];
   CPerson Tom="トムソーヤ";
   CPerson Huck("ハックルベリー","Finn");
   CPerson *Pooh = new CPerson("くまの","プーさん");

   // 出力
   Tom.PrintName();
   Huck.PrintName();
   Pooh.PrintName();
   
   // 動的オブジェクト削除
   delete Pooh;
}


このケースでは、CPersonクラスは次の3つのコンストラクタがあります。
 1. このクラスのオブジェクト配列作成出来る明示的なデフォルトコンストラクタ
 2. 1つのパラメータを持つコンストラクタ。これはパラメータとして完全な名前を取得し、名前と見つかった空白に応じてセカンドネームに分割します。
 3. 初期化リストが含まれている2つのパラメータを持つコンストラクタ。初期化子はm_second_name(姓) と m_first_name(名).


リストを用いた初期化が置換に割り当てられる事に注意してください。個々のメンバーは次のように初期化する必要があります。

クラスメンバ(式のリスト)


初期化リストでは、メンバーは任意の順番にする事が出来ます。
しかしクラスの全てのメンバは、メンバの定義順に従って初期化されます。

これは上記サンプルソースの第三のコンストラクタ(初期化リストを持つコンストラクタ)が良い例です。
1番目に定義されたメンバ(m_first_name)が最初に初期化され、その後に2番目に定義されたメンバ(m_second_name)が初期化されます。

デフォルトコンストラクタは基本クラスで宣言されていないと同時に、パラメータを有する1つ以上のコンストラクタを宣言している場合は、
常に初期化リスト内の基本クラスのコンストラクタの1つを呼び出す必要があります。
これは初期化リストのどこにあるかに関係無く、オブジェクト初期化時に最初に呼び出されます。


サンプルソース:
//+------------------------------------------------------------------+
//| ベースクラス                                                       
//+------------------------------------------------------------------+
class CFoo{
   string            m_name;

public:
   // 初期化リストを持つコンストラクタ
   CFoo(string name) : m_name(name) { Print(m_name);}
};

//+------------------------------------------------------------------+
//| CFooから派生したクラス
//+------------------------------------------------------------------+
class CBar : CFoo {
   CFoo              m_member;      // クラスメンバは親オブジェクトが持っています

public:
   // 初期化リストのデフォルトコンストラクタは親コンストラクタを呼び出します
   CBar(): m_member(_Symbol), CFoo("CBAR") {Print(__FUNCTION__);}
};

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart() {
   CBar bar;
}


上記のサンプルソースでは、barオブジェクトを作成する時にデフォルトコンストラクタCBar()を呼び出します。
ここで、最初に親CFooのコンストラクタが呼び出され、その後m_memberクラスメンバのコンストラクタが来ます。


デストラクタはクラスのオブジェクトが破壊された時に自動的に呼び出される特殊な関数です。
デストラクタはクラス名の前にチルダ(~)を記述します。
デストラクタの有無に関わらず、文字列や動的配列のオブジェクトは解放されます。
デストラクタが有る場合、これらのアクションはデストラクタを呼び出した後に実行されます。

デストラクタはvirtualキーワード宣言の有無に関わらず常にvirtualです。






クラスメソッドの定義


クラス関数メソッドは、クラス内及びクラス外の両方に定義する事が出来ます。
メソッドがクラス内で定義されている場合は、そのbodyはメソッド定義の右に来ます。

サンプルソース:
class CTetrisShape {
protected:
   int               m_type;
   int               m_xpos;
   int               m_ypos;
   int               m_xsize;
   int               m_ysize;
   int               m_prev_turn;
   int               m_turn;
   int               m_right_border;

public:
   void              CTetrisShape();

   void              SetRightBorder(int border) { m_right_border = border; }
   void              SetYPos(int ypos)          { m_ypos         = ypos;   }
   void              SetXPos(int xpos)          { m_xpos         = xpos;   }
   int               GetYPos()                   { return(m_ypos);         }
   int               GetXPos()                   { return(m_xpos);         }
   int               GetYSize()                  { return(m_ysize);        }
   int               GetXSize()                  { return(m_xsize);        }
   int               GetType()                   { return(m_type);         }
   void              Left()                      { m_xpos -= SHAPE_SIZE;    }
   void              Right()                     { m_xpos += SHAPE_SIZE;    }
   void              Rotate()                    { m_prev_turn = m_turn; if(++m_turn > 3) m_turn=0; }
   virtual void      Draw()                     { return;                 }

   virtual bool      CheckDown(int& pad_array[]);
   virtual bool      CheckLeft(int& side_row[]);
   virtual bool      CheckRight(int& side_row[]);
}; 



SetRightBorder(int border)関数からDraw()関数までは、CTetrisShapeクラス内部で直接定義されています。

CTetrisShape()コンストラクタと、CheckDown(int& pad_array[]), CheckLeft(int& side_row[]) , CheckRight(int& side_row[])メソッドは、
クラス内でのみ宣言されていますが、未だ定義はされていません。

これらの関数の定義するには更なるコードが必要です。

クラス外でメソッドを定義する為には、スコープ解決演算子を使用し、クラス名はスコープとして使用します。

サンプルソース:
#define SHAPE_SIZE 10
//+------------------------------------------------------------------+
//| 基本クラスのコンストラクタ                                   
//+------------------------------------------------------------------+
void CTetrisShape::CTetrisShape() {
   m_type         = 0;
   m_ypos         = 0;
   m_xpos         = 0;
   m_xsize        = SHAPE_SIZE;
   m_ysize        = SHAPE_SIZE;
   m_prev_turn    = 0;
   m_turn         = 0;
   m_right_border = 0;
}

//+------------------------------------------------------------------+
//| Checking ability to move down (for the stick and cube)           
//+------------------------------------------------------------------+
bool CTetrisShape::CheckDown(int& pad_array[])
  {
   int i,xsize = m_xsize/SHAPE_SIZE;

   for(i=0; i < xsize; i++) {
      if(m_ypos+m_ysize >= pad_array[i]) {
          return( false );
      }
   }

   return( true );
}







アクセス指定子(public, protected, private)


新しいクラスを作成する時は、外部からのメンバアクセス制限するをお勧めします。
private 又は protected キーワードを使用する事で制限する事が出来ます。
この場合、隠されたデータは同じクラスの関数メソッドからのみアクセス可能になります。

protectedキーワードを使用した場合、隠されたデータとクラスメソッドは継承クラスからアクセス出来ます

クラスのメンバやメソッドを完全にオープンにしてアクセス制限しない場合は、publicキーワードを使用します。

サンプルソース:
class CTetrisField {
private:
   int               m_score;                            
   int               m_ypos;                             
   int               m_field[FIELD_HEIGHT][FIELD_WIDTH]; 
   int               m_rows[FIELD_HEIGHT];               
   int               m_last_row;                         
   CTetrisShape     *m_shape;                            
   bool              m_bover;                            

public:
   void              CTetrisField() { m_shape=NULL; m_bover=false; }
   void              Init();
   void              Deinit();
   void              Down();
   void              Left();
   void              Right();
   void              Rotate();
   void              Drop();

private:
   void              NewShape();
   void              CheckAndDeleteRows();
   void              LabelOver();
}; 


public指定子の後(次のアクセス指定子前まで)に宣言されたクラスメンバとメソッドは、クラスオブジェクトへの参照で使用出来ます。
この例では、CTetrisField()関数からDrop()関数までが対象になります。

private指定子の後(次のアクセス指定子前まで)に宣言されたメンバは、このクラスのメンバ関数でのみ使用出来ます。

アクセス指定子は必ずコロン(:)で終了し、クラス定義内で何度も適用する事が出来ます。

基本クラスのメンバへのアクセスは、派生クラスの継承の際に再定義する事が出来ます。


■関連コンテンツ:
オブジェクト指向プログラミング


スポンサーリンク



Copyright ©2015 MT4でEA自作しちゃお〜 All Rights Reserved.


Top

inserted by FC2 system