スポンサーリンク
検索
カスタム検索
リファレンスツリー
オススメ

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


OOPの特徴は継承によるコード再利用促進です。
新しいクラスは基本クラスと呼ばれる既存クラスから作られます。
派生クラスは基本クラスのメンバを使用するだけでなく、それらを変更・補完する事が出来ます。

多くの型は既存の型のバリエーションです。
それは多くの場合、各バリエーションの為に新しいコードを開発する事が面倒です。
また、新しいコードは新しいエラーを意味します。
派生クラスは基本クラスの記述を継承するので、ソースコードの再開発と再試験は不要です。
継承関係は階層構造になっています。

階層は全ての多様性と複雑な要素をコピーする事が出来ます。
これはオブジェクトの分類を取り入れます。
例えば、元素周期表はガスを持っています。
ガスは全ての全周期元素に固有の特性を保有しています。

不活性ガスは、次に重要なサブクラスを構成します。
The hierarchy is that the inert gas, such as argon is a gas, and gas, in its turn, is part of the system.
このような階層は不活性ガスの挙動を簡単に解釈出来ます。
他の全ての要素についても同様に原子には陽子と電子が含まれている事が分かります。

不活性ガスは全てのガスのように常温で気体状態である事が分かります。
不活性ガスのサブクラスから、通常他元素と化学反応を起こしにくい事が分かります。
これは全て不活性ガスの特性です。

幾何学的形状の継承の例を考えてみましょう。
様々な単純な形状(円形、三角形、長方形、正方形等)を記述する為の最善の方法は、全て派生クラスの元である基本クラス(ADT)を作成する事です。

形状を記述する最も一般的なメンバを含む基本クラスCShapeを作成してみましょう。
これらのメンバは形状の特徴であるプロパティ(形状の型やメインアンカーポイント座標)を記述します。



例:
// 基本クラス
class CShape {

protected:
   int       m_type;                   // 形状タイプ
   int       m_xpos;                   // 基点のX座標
   int       m_ypos;                   // 基点のY座標

public:
             CShape(){m_type=0; m_xpos=0; m_ypos=0;} // コンストラクタ
   void      SetXPos(int x){ m_xpos=x; }             // Xを設定
   void      SetYPos(int y){ m_ypos=y; }             // Yを設定
};



次に基本クラスから派生した新しいクラスを作成し、必要なフィールドを追加し、それぞれ特定クラスを指定します。
円形には半径値を含むメンバを追加する必要があります。
正方形は側面値によって特徴付けられます。
したがって、基本クラスCShapeから継承された派生クラスは次のように宣言されます。


例:
// 派生クラス(円形用)
class CCircle : public CShape {           // コロンの後に基本クラスを定義する

private:
   int             m_radius;              // 円の半径
 
public:
                   CCircle(){ m_type=1; } // コンストラクタ タイプ1
};



正方形クラス宣言も似ています。

// 派生クラス(正方形用)
class CSquare  : public CShape {           // コロンの後に基本クラスを定義する

private:
   int             m_square_side;          // 正方形の側面
 
public:
                   CSquare(){ m_type=2; } // コンストラクタ タイプ2
};



オブジェクト作成時に基本クラスのコンストラクタが最初に呼び出される事に注意する必要があります。
その後派生クラスのコンストラクタが呼び出されます。
オブジェクトが最初に破棄された場合、派生クラスのデストラクタが呼び出され、その後に基本クラスのデストラクタが呼び出されます。

このように、基本クラスの中で一般的なメンバを宣言する事によって、特定のクラスを指定して派生クラスにメンバを追加する事が出来ます。
継承は何度も再利用する事が出来る強力なコードライブラリを作成する事が出来ます。

既存のものから派生クラスを作成する為の構文は次の通りです。

継承の構文
class 派生クラス名 : (public | protected | private のいずれか)  基本クラス名 {
    クラスメンバの宣言
};



派生クラスの側面の一つは、そのメンバの後継者の可視性です。
public,protected,privateキーワードはどの程度使用可能かを示すもので、基本クラスのメンバが派生クラスの為に利用します。
派生クラスヘッダのコロンの後にpublicキーワードを書いた場合、ベースクラスCShapeのprotectedとpublicメンバは、派生クラスCCircleのprotectedとpublicメンバとして継承される必要がある事を示します。

基本クラスのprivateメンバは派生クラスでは使用出来ません。
public継承は派生クラス(CCircleとCSquare)がCShapesである事を意味します。
CSquareは形状(CShape)ですが、形状は必ずしも正方形である必要はありません。

派生クラスは基本クラスの変形例で、これは基本クラスのprotectedとpublicメンバを継承します。
基本クラスのコンストラクタとデストラクタは継承出来ません。
基本クラスのメンバに加えて派生クラスに新しいメンバが追加されます。

派生クラスは、基本クラスとは違うメンバ関数の実装を含む事が出来ます。
これはオーバーロードとは違い、同じ関数名の意味が異なるシグネチャの為異なっていても良いのです。

protected継承は、基本クラスのpublicとprotectedメンバは派生クラスのprotectedメンバになります。
pribate継承は、基本クラスのpublicとprotectedメンバは派生クラスのprivateメンバになります。

protectedとprivate継承は、「派生クラスのオブジェクトは基本クラスのオブジェクトである」という関係ではありません。
protectedとprivate継承はまれであり、慎重に使用する必要があります。

継承のタイプ(public,protected,private)は派生クラスが基本クラスメンバにアクセスする方法に影響を及ぼさない事を理解するべきです。
継承のいずれかのタイプでは、基本クラスでpublicとprotectedのアクセス指定が宣言されたメンバのみが派生クラスで利用出来ます。

次の例でそれを考えてみましょう。


//+------------------------------------------------------------------+
//| 複数のアクセスタイプを持つ基本クラス                            |
//+------------------------------------------------------------------+
class CBaseClass {

private:             // privateメンバは派生クラスで利用出来ません
   int               m_member;

protected:           // protectedメソッドは基本クラスと派生クラスで利用出来ます
   int               Member(){ return ( m_member ); }

public:              // クラスコンストラクタは全てのクラスメンバから利用出来ます
                     CBaseClass(){ m_member=5; return; };

private:             // m_memberに値を設定するpribateメソッド
   void              Member(int value) { m_member=value;};
 
};

//+------------------------------------------------------------------+
//| エラーが発生する派生クラス                                        |
//+------------------------------------------------------------------+
class CDerived: public CBaseClass { // 継承はpublicがデフォルトの為、public指定は省略可能です

public:

   void Func() { // 派生クラスで、基本クラスメンバを呼び出す関数を定義

      // 基本クラスのprivateメンバを変更しようとする処理
      m_member = 0;        // エラーになります。基本クラスのprivateメンバは変更出来ません
      Member(0);           // エラーになります。基本クラスのprivateメソッドは、派生クラスでは利用出来ません。

      // 基本クラスのメンバを使用する処理
      Print(m_member);    // エラーになります。基本クラスのprivateメンバは利用出来ません。
      Print(Member());    // エラーになりません。基本クラスのprotectedメソッドは派生クラスでも利用可能です。
   }

};



上記の例では、CBaseClassは唯一のpublicメソッドがコンストラクタです。
コンストラクタはクラスオブジェクトを作成する時に自動的に呼び出されます。
privateメンバm_memberとprotectedメソッドMember()は外から呼び出す事が出来ません。
しかしpublic継承の場合は、基本クラスのMember()メソッドは派生クラスから利用出来るようになります。

protected継承の場合は、基本クラスのpublicとprotectedメンバは全て派生クラスのprotectedメンバになります。
もし基本クラスのpublicデータメンバとpublicメソッドが外からアクセスする場合、protected継承では派生クラスまたは派生クラスの派生クラスからのみ利用可能を意味します。



//+------------------------------------------------------------------+
//| 複数のアクセスタイプを持つ基本クラス     
//+------------------------------------------------------------------+
class CBaseMathClass {

private:             // privateメンバは派生クラスから利用出来ません
   double            m_Pi;

public:              // m_Piの設定と取得
   void              SetPI(double v){ m_Pi=v; return; };
   double            GetPI()        { return m_Pi;    };

public:              // クラスコンストラクタは全てのメンバから利用出来ます
                     CBaseMathClass() { SetPI(3.14);  PrintFormat("%s",__FUNCTION__); };
};

//+------------------------------------------------------------------+
//| m_Piを変更する事が出来ない派生クラス
//+------------------------------------------------------------------+
class CProtectedChildClass: protected CBaseMathClass { // protected継承

private:
   double            m_radius;

public:              // 派生クラスのpublicメソッド
   void              SetRadius(double r){ m_radius = r; return;     };
   double            GetCircleLength()  { return GetPI() * m_radius;};
};

//+------------------------------------------------------------------+
//| スクリプト起動イベント
//+------------------------------------------------------------------+
void OnStart() {

   // 派生クラス作成時、基本クラスのコンストラクタが自動的に呼び出されます
   CProtectedChildClass pt;

   // 半径を指定
   pt.SetRadius(10);
   PrintFormat( "長さ = %G",pt.GetCircleLength());

   // SetPI()はprotectedメソッドの為、コメントアウトを解除した場合はコンパイルエラーになります
   // pt.SetPI(3); 
 
   // 基本クラスの変数を宣言し、Pi定数を10に設定する
   CBaseMathClass bc;
   bc.SetPI(10);

   // 結果出力
   PrintFormat( "bc.GetPI() = %G ",bc.GetPI());
}




この例では、基本クラスCBaseMathClassのSetPI()とGetPi()メソッドがプログラムの任意の場所から呼び出せる事を示しています。
しかし同時に、派生するCProtectedChildClassでは、これらのメソッドはCProtectedChildClassクラスまたはその派生クラスからのみ呼び出せます。

private継承の場合は、基本クラスのpublicとprotectedの全メンバは派生クラスのpribateになり、派生クラスから呼び出せません。

MQL4は多重継承を持っていません。
■関連コンテンツ:
構造体
クラス
スポンサーリンク



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


Top

inserted by FC2 system