たったこれだけです。例題のプログラムを書いてみましょう。[手順] 1.継承元クラスで、オーバーライドされる関数を virtualとして宣言する(仮想関数といいます) 2.継承先クラスで、オーバーライドする関数を普通に宣言する
#include <iostream.h> class Moto { public: virtual int kaso(); }; class Saki : public Moto { public: int kaso(); }; int Moto::kaso(void) { cout << "継承元です" << endl; return 0; } int Saki::kaso(void) { cout << "オーバーライドしました" << endl; return 0; } int main(void) { Saki a; Moto b; a.kaso(); b.kaso(); return 0; }
たったこれだけのプログラムです。継承元のクラスで
基本になる関数をvirtual宣言しておいて継承先の
クラスで、この関数の機能を拡張して使うときなどに利用します。
さて、ここでクラスへのポインタについて考えてみます。
これも、
#include <iostream.h> class Pointer { public: int a; Pointer(); ~Pointer(){}; }; Pointer::Pointer(void) { a = 100; } int main(void) { Pointer x; Pointer *ptr; ptr = &x; cout << "x.a は " << x.a << endl; cout << "ptr->a は " << ptr->a << endl; cout << "(*ptr).a は" << (*ptr).a << endl; return 0; }
結果はどれも同じですね。
さて、ポインタを使ってメンバ関数を呼び出すときも
全く同じ要領です。
#include <iostream.h> class Moto { public: virtual int kansu(void); }; class Saki : public Moto { public: int kansu(void); }; int Moto::kansu(void) { cout << "元のクラスです" << endl; return 0; } int Saki::kansu(void) { cout << "先のクラスです" << endl; return 0; } int main(void) { Moto moto, *p_moto; Saki saki, *p_saki; p_moto = &moto; p_saki = &saki; (*p_moto).kansu(); (*p_saki).kansu(); p_moto->kansu(); p_saki->kansu(); return 0; }
結果も予想通りと思います。ここで注意すべきことは、
MotoとかSakiとかいうのは、ユーザーが新しく定義した
データ型と考えることができます。
当然MotoとSakiは違うデータ型でしょう。
ところが、上のプログラムで
としても、コンパイラは注意してくれません。 このような使い方は間違いではありませんが (それどころか大変便利な使い方があります)、 バグが発生すると大変わかりにくいです。 したがって初心者の方にはあまりお勧めできません。p_moto = &saki;
Update Jan/15/1997 By Y.Kumei