オーバーライド
classを継承すると継承元クラスの関数が使えるので便利になりました。
ただ継承したときに処理を変更したい場合もあります。
そういう時に継承したクラスで引数と戻り値が同じ関数を再定義することができます。
これをオーバーライドと言います。
class Base { public: void Print(void) { printf("Base\n"); } }; class Child : public Base { public: void Print(void) { printf("Child\n"); } }; void main(void) { Base base; Child child; base.Print(); child.Print(); }
出力結果
Base
Child
このようにオーバーライドを使用することで関数の内容を変えることができます。
仮想関数
オーバーライドを使うことで関数の内容を変えることが出来ました。
ただこの対応では不十分な場合があります。
void main(void) { Base* base = new Child; base->Print(); }
出力結果
Base
このように継承したクラスの実体を作成してBaseのポインタとして保持した場合。
Printを呼び出すとBaseの関数が呼び出されてしまいます。
今回のような例ではChildのポインタとして保持すればいいのですが、場合によっては継承元のクラスのポインタとして使いたいこともあります。
そんな時に使えるのが仮想関数です。
class Base { public: virtual void Print(void) { printf("Base\n"); } };
関数の戻り値の前に virtual と記述することで仮想関数として扱われます。
仮想関数を使うことでBaseクラスのポインタに格納された場合でも継承先でオーバーライドした関数の情報を保持できるようになります。
使い方は仮想関数を定義する以外は全て同じです。
class Child : public Base { public: void Print(void) { printf("Child\n"); } }; void main(void) { Base* base = new Child; base->Print(); }
出力結果
Child
このように同じ関数を呼び出しているのに異なる振る舞いをすることを
多様性(ポリモーフィズム)
と呼びます。
純粋仮想関数
仮想関数を使うことで継承先で異なる振る舞いにすることが出来ました。
ただ継承元のクラスでは実装の必要のない継承を前提としたクラスを作りたい場合があります。
そんな時は純粋仮想関数を使うことで実装の無い仮想関数を作ることができます。
class Base { public: virtual void Print(void) = 0; };
このように virtual を付けた関数の定義を = 0 とすることで実装の無い関数。
純粋仮想関数
を定義できます。
純粋仮想関数を持つクラスは実体化することができません。
こういったクラスを抽象クラスと呼びます。
抽象クラスを継承したクラスでは必ず純粋仮想関数とした関数を実装する必要があります。
抽象クラスを使うことで振る舞いを継承先で切り替えることができるようになります。
そうやってハードウェアなどの固有の処理を継承先に任せることでマルチプラットフォームで動作するような実装も可能になります。
これらが使えることによるメリットはかなり大きいのでC++等のオブジェクト指向のプログラムでは積極的に取り入れていきましょう!