[C++] 継承クラスでの、仮想関数による再定義(オーバーライド)と、普通の関数の再定義(隠ぺい)の違い

Pocket

よくある仮想関数を使ったポリモーフィズム(多様性)の例とは少し違うけど
(複数の種類の派生クラスのアドレスを、親クラスのポインタに代入するやつ)、
メソッドをオーバーライドした場合と、隠ぺいした場合の動作の違いを例示すると、
こんな感じのソースになる。
[cc lang=”c++” lines=”-1″]
#include
using std::cout;
using std::endl;

class CBase {
public:
void funcCall(char *c) {
cout << c << func01() << "," << func02() << endl; } virtual char *func01() {return " Base01";} char *func02() {return " Base02";} }; class CDerived : public CBase { public: char *func01() {return " Derv01";} // オーバーライド char *func02() {return " Derv02";} // 隠ぺい }; int main() { CBase obj01; CDerived obj02; // [1] obj01.funcCall("BaseClass:"); // [2] obj02.funcCall("DervClass:"); // [3] cout << "DervClass:" << obj02.func01() << "," << obj02.func02() << endl; return 0; } [/cc] obj01 は CBase クラスなので、当然 CBase の func01 と func02 の関数が呼ばれる。([1]) 一方の obj02 は、 CDerived クラスだが、 funcCall 関数は CBase クラスのメソッドなので、 func01 と func02 を funcCall 関数から呼ぶと、 オーバーライドされている func01 は CDerived のものが呼ばれ、 単に同じ関数名で隠ぺいしているだけの func02 は、 CBase のものが呼ばれる。([2]) しかし、 obj02 の func01 と func02 を直接呼べば、両方とも CDerived のものが呼ばれる。([3]) 従って、出力結果は以下の様になる。 実行結果

つまるところ、 CDerived クラスの func02 関数は、
CDerived という新たなスコープで func02 関数が定義されているだけなので、
CBase というスコープ (funcCall 関数内からの呼び出し) からは CBase の func02 が呼ばれ、
CDerivedというスコープ (obj02 のメソッドとしての呼び出し) からはCDerivedのfunc02が呼ばれると言うわけだ。

ブロックスコープで例えてみるなら、以下のソースの出力が
[cc lang=”c++” line_numbers=”false”]
// 元のスコープ
int a = 8;
{ // ブロックによる入れ子スコープ
int a = 16; // “元のスコープ”のa変数を隠ぺいする
cout << a << endl; } cout << a << endl; [/cc]

16
8

 
 となることに疑念はないだろう。

1 thought on “[C++] 継承クラスでの、仮想関数による再定義(オーバーライド)と、普通の関数の再定義(隠ぺい)の違い

  1. ピンバック: Aqua Ware つぶやきブログ » WM_SIZEをハンドルしないCDialogResizeを作る

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください