非仮想メソッドのオーバーライド


84

Visual C ++ 2010でこのシナリオを想定しましょう。

#include <iostream>
#include <conio.h>

using namespace std;

class Base
{
public:
    int b;
    void Display()
    {
        cout<<"Base: Non-virtual display."<<endl;
    };
    virtual void vDisplay()
    {
        cout<<"Base: Virtual display."<<endl;
    };
};

class Derived : public Base
{
public:
    int d;
    void Display()
    {
        cout<<"Derived: Non-virtual display."<<endl;
    };
    virtual void vDisplay()
    {
        cout<<"Derived: Virtual display."<<endl;
    };
};

int main()
{
    Base ba;
    Derived de;

    ba.Display();
    ba.vDisplay();
    de.Display();
    de.vDisplay();

    _getch();
    return 0;
};

理論的には、この小さなアプリケーションの出力は次のようになります。

  • ベース:非仮想ディスプレイ。
  • ベース:仮想ディスプレイ。
  • ベース:非仮想ディスプレイ。
  • 派生:仮想ディスプレイ。

BaseクラスのDisplayメソッドは仮想メソッドではないため、Derivedクラスはそれをオーバーライドできないはずです。正しい?

問題は、アプリケーションを実行すると、次のように出力されることです。

  • ベース:非仮想ディスプレイ。
  • ベース:仮想ディスプレイ。
  • 派生:非仮想ディスプレイ。
  • 派生:仮想ディスプレイ。

そのため、仮想メソッドの概念を理解していなかったか、Visual C ++で何か奇妙なことが起こりました。

誰かが説明を手伝ってくれませんか?


あなたは絶対にBase:非仮想ディスプレイを持っているでしょう行をに変更するときde.Base::Display()
v.oddou 2014年

回答:


128

ええ、あなたは少し誤解しています。

この場合、派生クラスの同じ名前のメソッドは親メソッドを非表示にします。そうでない場合は、基本クラスの非仮想メソッドと同じ名前のメソッドを作成しようとすると、エラーがスローされると想像できます。それは許可されており、問題はありません。メソッドを実行したとおりに直接呼び出すと、正常に呼び出されます。

ただし、非仮想であるため、ポリモーフィズムを可能にするC ++メソッドルックアップメカニズムは使用されません。したがって、たとえば、派生クラスのインスタンスを作成したが、基本クラスへのポインタを介して「Display」メソッドを呼び出した場合、基本のメソッドが呼び出されますが、「vDisplay」の場合は派生メソッドが呼び出されます。

たとえば、次の行を追加してみてください。

Base *b = &ba;
b->Display();
b->vDisplay();
b = &de;
b->Display();
b->vDisplay();

...そして期待どおりに出力を観察します:

ベース:非仮想ディスプレイ。
ベース:仮想ディスプレイ。
ベース:非仮想ディスプレイ。
派生:仮想ディスプレイ。


こんにちは@ sje397、お返事ありがとうございます。あなたが言ったように、基本クラスへのポインタを介してメソッドを呼び出す例を書くことができますか?ありがとうございました!
Leif Lazar 2012年

また、前述したように、スコープ解決構文を使用して、派生インスタンスから(非仮想)基本メソッドを呼び出すこともできます。
v.oddou 2014年

1
したがって、念のため、仮想として宣言するかどうかに関係なく、基本クラスでメソッドを定義し、派生クラスでメソッドをオーバーライドできます。唯一の違いは、基本ポインタが派生クラスオブジェクトを指している場合、そのメソッドを呼び出すと、仮想でない場合は基本クラスのメソッドが計算され、仮想の場合は派生クラスのメソッドが計算されることです。そうですか?他に違いはありますか?
SexyBeast 2014年

@Cupidvogelうん、その通りです。「仮想」と宣言すると、C ++はメカニズムを使用してポリモーフィズムをサポートし、基本クラスポインターを介して呼び出すときに、メソッドのより派生したバージョンがあるかどうかを確認します。他の違いは考えられません。
sje397 2014年

ヘッダーファイルのみを変更するだけで十分ですか?または、ソースを「virtual」キーワードでコンパイルする必要がありますか?
Paul Knopf 2015

14

はい、あなたは少し誤解しています:

純粋仮想関数:

virtual void fun1()=0 ->派生クラスでオーバーライドする必要があります

仮想機能:

virtual void fun2() ->オーバーライドできます

通常の機能:

void fun3() ->オーバーライドしないでください

ランタイムポリモーフィズムを実現するには、C ++で仮想関数をオーバーライドする必要があります


5

静的バインディングと動的バインディングのコンテキストでそれを見る方が良いかもしれないと思います。

メソッドが非仮想である場合(Javaとは異なりC ++ではすでにデフォルトになっています)、メソッドはコンパイル時に呼び出し元にバインドされます。これは、実行時にポイントされる実際のオブジェクトを知ることは不可能です。したがって、変数タイプが重要なのは「ベース」です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.