純粋仮想関数
基本クラスでは,単に主要なメンバ関数と 変数を宣言し, 必要なものは派生クラスで用意することが多い. すなわち,基本クラスのオブジェクトに対する操作は行わず, これを継承した派生クラスのオブジェクトに対して 操作を行うことが多い.
この場合には, 基本クラスには仮想関数を使用するための 名前だけで実態のないメンバ関数を用意しておけばよいことになる. このとき,純粋仮想関数を使用する.
純粋仮想関数とは, 関数定義を持たず,次のような形式をしている.
virtual 型名 関数名(引数リスト) = 0;
この定義では,関数本体が 0 に等しいと定義している. すなわち,関数本体が存在しないことを表す.
このような関数を持つクラスを継承する派生クラスでは, 実体のない関数を呼ぶことができないため, 必ずその関数を再定義しなおさなければならない.
少なくとも 1 つの純粋仮想関数を含んでいるクラスを 抽象クラス と呼ぶ. 抽象クラスは,本体のない関数を含んでいるため, そのクラスのオブジェクトを作成できない. 抽象クラスへのポインタは作成でき, 実行時のポリモーフィズムは実現できる.
class date { int y, /* year */ m, /* month */ d; /* day */ public: virtual bool leapyear() = 0; /* 純粋仮想関数 */ int getyear() { return y; } }; class seireki: public date { public: bool leapyear() { /* 閏年 */ return (getyear() % 400 == 0) || (getyear() % 4 == 0) && (getyear() % 100 != 0); } /* 純粋仮想関数を持つクラスを継承しているクラスでは, 必ず再定義する */ }; class heisei: public date { public: bool leapyear() { /* 閏年 */ return ((getyear() + 1988) % 400 == 0) || ((getyear() + 1988) % 4 == 0) && ((getyear()+ 1988) % 100 != 0); } /* 純粋仮想関数を持つクラスを継承しているクラスでは, 必ず再定義する */ };
上の例では,
leapyear
は基本クラス date
の中で
純粋仮想関数として定義されている.
よってクラス date
は抽象クラスとなり
そのオブジェクトは作成できない.
西暦のクラスと平成のクラスを date
の派生クラスとして
定義しており,
それぞれで閏年かどうかを判定する関数 leapyear
を
再定義している.
よって,
int main() { date *p; heisei nen; seireki year; ... date = &nen; if (date->leapyear()) { ... } date = &year; if (date->leapyear()) { ... } }のように記述できる.