9章 オーバーライド
http://www.geocities.jp/ky_webid/cpp/language/009.html
前回継承というものを学びました。
今回このオーバーライドというものなのですが、継承したサブクラスでスーパークラスと同名のメンバ関数を定義し、上書きできるというもののようです。
とにかくまず実装してみましょう。
#include <iostream> class CBase { public: virtual void foo (); }; class CSub : public CBase { public: void foo (); }; void CBase::foo () { std::cout << "CBase::foo" << std::endl; } void CSub::foo () { std::cout << "CSub::foo" << std::endl; } int main () { CBase objb; CSub objs; objb.foo(); objs.foo(); return 0; }
$ main CBase::foo CSub::foo
できました。なるほどです。
これやはりvirtualはつけないと動かないですよね、と思ってためしにvirtualなしでやってみても動きました!えええ。
そこで色々調べてみたところ、どういうことか分かりました。
なるほど。
少しまとめます。C++は基本的にvirtualつけようかつけまいが、メンバ関数の上書きそのものはできます。
ではvirtual有り無しで何が違うのかというと、そのメンバ関数を呼び出している別のメンバ関数があった場合に挙動が変わります。
実際に実装を見てみましょう。まずはvirtual無しの場合です。
#include <iostream> class CBase { public: void foo (); void call (); }; class CSub : public CBase { public: void foo (); }; void CBase::foo () { std::cout << "CBase::foo" << std::endl; } void CBase::call () { foo(); } void CSub::foo () { std::cout << "CSub::foo" << std::endl; } int main () { CBase objb; CSub objs; objb.call(); objs.call(); return 0; }
$ main CBase::foo CBase::foo
スーパークラスCBaseにcallというメンバ関数を持たせてfoo関数を呼び出す処理をしています。
このcall関数をサブクラスCSubから呼び出してもCSubのfooじゃなくてCBaseのfooが呼び出されていますね。
あくまでfoo関数を上書きしただけなのでcallで呼び出しているfooは常にCBaseのfooを見るということになります。
そしてvirtualを使えばこの挙動を変えることができるというわけです。
class CBase { public: virtual void foo (); // virtualを付加 void call (); };
$ main CBase::foo CSub::foo
変わりましたね。
virtualをつけたfoo関数を呼び出しているcall関数がサブクラスCSubから呼び出された場合、そのCSubで定義されているfoo関数を見るようになるということです。
この機能のことをオーバーライドというみたいです。virtualをつけない関数の再定義は単なる関数の上書きということらしいです。