第12章 関数のオーバーライド


関数のオーバーライドと混同しやすいものにオーバーロード というのがありました。(筆者も時々間違えます) 簡単にいうと、オーバーライドとは継承元の関数を継承先で、書き換えてしまうことです。

[手順] 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宣言しておいて継承先の クラスで、この関数の機能を拡張して使うときなどに利用します。

さて、ここでクラスへのポインタについて考えてみます。 これも、C言語編第28章でやった 構造体へのポインタとほとんど同じです。これも、くどくどと 説明を書くより、例題を示した方がわかりやすいでしょう。

#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;

としても、コンパイラは注意してくれません。 このような使い方は間違いではありませんが (それどころか大変便利な使い方があります)、 バグが発生すると大変わかりにくいです。 したがって初心者の方にはあまりお勧めできません。


[C++Index] [総合Index] [Previous Chapter] [Next Chapter]

Update Jan/15/1997 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。