1

C++ の継承メカニズムをより深く分析しようとしているときに、次の例に出くわしました。

#include<iostream>

using namespace std;

class Base {
public:
    virtual void f(){
    cout << "Base.f" << endl; 
    }
};

class Left : public Base { //NOT VIRTUAL!!!
public:
void g(){ 
        f();
    }     
};

class Right : public Base{
public:
    virtual void f(){
    cout << "Right.f" << endl; 
    }
};

class Bottom : public Left, public Right{
public:
    Bottom(int arg){ }
    //void f() { }
};

int main(int argc,char **argv)
{
    Bottom* b = new Bottom(23);
    b->g();
}

呼び出していることは明らかです

b->f()

はあいまいなのでf()、オブジェクト Bottom に固有のメソッドはありません。今、呼び出し

b->g()

正常に動作し、印刷されます

Base.f

まあ、私がこれを見る限り:

  1. g()静的タイプは Bottom であり、非仮想であるため、そのメソッドを呼び出します
  2. g()メソッドは Left から継承されているため、この継承されたメソッドを呼び出します
  3. ここでg()、左で仮想メソッドを呼び出そうとしますf()。C++ の仕様によるとf()、ポインタの動的型 (Bottom) のメソッドを呼び出します。

BUT Bottomにはメソッドがありませんf()...少なくとも一意のものではありません。このプログラムが実行されるのはなぜですかLeft::Base::f()、または単に呼び出しが下からあいまいでRight::Base::f()あると述べられないのはなぜですか?f()

4

2 に答える 2

2

簡単な答えは、(あなたが指摘したように) にBottomは methodf()がないため、呼び出そうとする必要がないということです。

BottomLeftにはとの 2 つのサブオブジェクトが含まれていRightます。それらのそれぞれは から継承してBaseいるためBottom、メンバー関数Left::f()およびが含まれていますが、 は含まれてRight::f()いませんBottom::f()。Bottom は (たとえばLeft::f()を使用して)オーバーライドしないため、は の一意の最終オーバーライドです。Right::f()Base::f()Left::g()

参照。C++03 標準の 10.3.9 の例。

于 2012-04-15T21:40:23.363 に答える
1

仮想継承がないため、Baseオブジェクトにはオブジェクトの 2 つのコピーがありBottomます。Leftしかし、が定義されている階層を上に移動するg()と、単一のBaseサブオブジェクトがあり、それが呼び出されます。Left(または) でオーバーライドされていないためBottom、バージョンが呼び出されBaseます。それ自身のサブオブジェクトRight::f()のみをオーバーライドすることに注意してください。f()Base

fを直接呼び出すのBottomはあいまいです。なぜなら、そこには no がありf()Bottomそのベースを調べようとして and が見つかりLeft::Base::fRight::Base::fコンパイラは 2 つのうちどちらを使用するかを知らないからです。

于 2012-04-15T21:54:54.000 に答える