ポリモーフィズムは継承によって関連した異なるオブジェクトクラスで同じ関数要素を呼び出す時に使われます。
これは基本クラスの動作を記述する普遍的なメカニズムを作成するのに役に立ち、子孫クラスにも役に立ちます。
基本クラスCShapeの開発を続けましょう。
GetAera()関数メンバを定義し、形状の面積を計算するように設計します。
基本クラスから継承する事によって生成された全ての下位クラスは、特定の形状の面積を計算する規則に従って関数を再定義します。
正方形(CSquareクラス)では面積がその側面を介して計算され、円(CCircleクラス)では面積が半径等で表現されます。
基本クラスと全ての子孫クラスの両方のオブジェクトを格納する事が出来るCShape型のオブジェクト配列を作成する事が出来ます。
さらに配列の各要素に対して同じ関数を呼び出す事が出来ます。
例:
class CShape {
protected:
int m_type;
int m_xpos;
int m_ypos;
public:
void CShape() { m_type=0; };
int GetType(){ return( m_type );};
virtual
double GetArea(){ return (0); }
};
今、派生クラスの全てがゼロの値を返すメンバ関数getArea()を持っています。
この関数の実装は各子孫で異なります。
class CCircle : public CShape {
private:
double m_radius;
public:
void CCircle(){ m_type=1; };
void SetRadius(double r){ m_radius = r;};
virtual double GetArea(){ return (3.14 * m_radius * m_radius);}
};
正方形クラスの宣言も同じです
class CSquare : public CShape {
private:
double m_square_side;
public:
void CSquare(){ m_type=2; };
void SetSide(double s){ m_square_side = s;};
virtual double GetArea(){ return ( m_square_side * m_square_side);}
};
正方形と面の面積を計算する為に、m_radiusとm_square_sideの値が必要となるので、対応するクラス宣言にSetRadius()とSetSide()関数を追加しました。
1つの基本型CShapeから派生した異なるタイプのオブジェクト(CCircleとCSquare)がプログラムで使用されていると仮定します。
ポリモーフィズムは基本クラスCShapeのオブジェクト配列を作成する事が出来ますが、配列の宣言時はこれらのオブジェクトは未だ不明で型も定義されていません。
配列の各要素に含まれるオブジェクトタイプの決定は、プログラム実行中に直接行われます。
これは適切なクラスのオブジェクトの
動的作成が関係し、オブジェクトの代わりに
オブジェクトポインタを使用します。
new演算子はオブジェクトの動的作成に使用します。
このようなオブジェクトは個別に
delete演算子を使用して明示的に削除する必要があります。
CShape型のポインタ配列を宣言し、次のスクリプトの例に示すように各要素(new Class_Name)の為の適切な型のオブジェクトを作成します。
void OnStart() {
CShape *shapes[5];
CCircle *circle = new CCircle();
circle.SetRadius(2.5);
shapes[0] = circle;
circle = new CCircle();
shapes[1] = circle;
circle.SetRadius(5);
shapes[2] = NULL;
CSquare *square = new CSquare();
square.SetSide(5);
shapes[3] = square;
square = new CSquare();
square.SetSide(10);
shapes[4] = square;
int total = ArraySize(shapes);
for( int i=0; i < 5; i++ ) {
if ( CheckPointer( shapes[i]) != POINTER_INVALID ) {
PrintFormat( " オブジェクトタイプ: %d , 面積: %G",
shapes[i].GetType(), shapes[i].GetArea()
);
} else {
PrintFormat("オブジェクトshapes[%d]は初期化されていません。 ポインタは%s",
i , EnumToString(CheckPointer(shapes[i]))
);
}
}
for( int i=0; i < total ;i++) {
if ( CheckPointer(shapes[i]) == POINTER_DYNAMIC ) {
PrintFormat("オブジェクトshapes[%d]を削除",i);
delete shapes[i];
}
}
}
delete演算子を使用してオブジェクトを削除する時は注意する必要があります。
その
ポインタのタイプをチェックする必要があります。
POINTER_DYNAMICポインタを持ったオブジェクトのみdelete演算子で削除する事が出来ます。
他タイプのポインタの場合はエラーが返されます。
しかし、継承時の関数の再定義に加えて、ポリモーフィズムもまたクラス内の異なるパラメータセット持った同じ関数が実装が含まれます。
これは同じ名前の複数の関数を持ったクラスを意味します、しかしパラメータセットと型が異なります。
この場合、ポリモーフィズムは関数の
オーバーロードを介して実装されます。