次の例として,画面上を運動する点MovingPointを定義してみよう. この点は,現在の点の座標に加えて,点の速度ベクトルを持っている. これをクラスで表現すると,こんな感じになるだろう.
class MovingPoint {
private:
vector2D coord;
vector2D velocity;
int color;
public:
MovingPoint(int x, int y, int vx, int vy, int col);
‾MovingPoint();
....
};
このMovingPointの定義は,Pointの定義に似ている.
両方とも「画面上の点」という性質を共有しているのだから,当然だ.
コンストラクタMovingPoint()や,デストラクタ‾MovingPoint()
の記述も,Pointのコンストラクタやデストラクタの記述に
似たものになるだろう.
このように,あるクラスの性質を包含した別なクラスを作る場合に 便利なのが「継承」(インヘリタンス)という機能だ.これは, あるクラスを作る場合に,既存のクラスのメンバ変数やメンバ関数を そっくりそのまま再利用するという機能である.この例の場合, こんな感じになる.
class MovingPoint : public Point {
private:
vector2D velocity;
public:
MovingPoint(int x, int y, int vx, int vy, int col)
: Point(x,y,col) { ... }
‾MovingPoint();
....
};
点の座標と色の情報は,クラスPointの定義に含まれるので,
MovingPointではこれをもう一度記述する必要はない.
このとき,クラスPointを基底クラス(base class),MovingPoint
を派生クラス(derived class)と呼ぶ.派生クラスでは,基底クラスの
メンバ変数やメンバ関数が継承されるので,
そのまま使うことができる.ただし,コンストラクタは継承されないので
注意が必要だ.
コンストラクタMovingPoint()では,メンバ変数の初期化と似たような 書式で,基底クラスのコンストラクタを呼び出している.この処理により, MovingPointのコンストラクタでは,「最初に画面に点を打つ」 などの初期処理を記述しなくてもすむし,点の初期化に必要な処理がもし 変わったとしても,Pointの定義だけを変えれば自動的に MovingPointの挙動も変更されるのだ.ちなみにデストラクタについては, MovingPoint()が呼ばれると,その基底クラスのデストラクタも自動的に 呼び出されるようになっている.
ところで,このままだと,MovingPointのメンバ関数の中では Pointのメンバ変数を直接いじることができない.なぜかというと, Pointのメンバ変数はprivateだからだ.これでは不便なので, 「自分のメンバ関数と,自分の派生クラスのメンバ関数からのアクセスを許す」 という指定がある.これには,次のようにする.
class Point {
protected:
vector2D coord;
int color;
....
};
protected:というのがその指定だ.Pointと関係ない関数の中では,
private:もprotected:もまったく同じだが,
Pointの派生クラスのメンバ関数からは,protected:に指定された
変数は見ることができる.だから,クラスを記述する際に,あるメンバを
private:にするかprotected:にするかは,そのクラスの派生クラス
からアクセスされてもいいかどうかを考えて決めなくてはならない.