1

次のコードサンプルがあります。

class A
{
public:
    A(int a):AA(a) {};

    int AA;

    virtual int Test() 
    {
        return AA;
    };
};

class B
{
public:
    B(int b):BB(b) {};

    int BB;

    virtual int Test() 
    {
        return BB;
    };
};

class C:public A, public B
{
public:
    C(int a, int b, int c) :A(a),B(b),CC(c) {};

    int CC;
};

int main()
{
    A *a = new C(1,2,3);
    B *b = new C(1,2,3);
    C *c = new C(1,2,3);


    int x = a->Test() ; // this is 1
    int y = b->Test() ; // this is 2
//  int z = c->Test() ; // this does not compile

    return 0;
}

オブジェクトaはCであり、したがって、両方とも同じTest()関数を持つAとBを継承するため、a-> Test()とb-> Test()の呼び出しもあいまいになると予想していました。ただし、どちらも、オブジェクトが実際にあるタイプではなく、削除されたタイプに対応する実装を呼び出します。

これらの呼び出しがあいまいでない理由を誰かが説明できますか?C ++は常にこのように動作しますか?

4

2 に答える 2

2

実際、Cインスタンスは完全なAインスタンスと完全なBインスタンスの両方です(したがって、AメソッドとBメソッドのコピーを保持します)

aはA*であるため、コンパイラはCインスタンス内にあるA仮想テーブルコピーを使用します。bはB *であるため、コンパイラはCインスタンス内にあるB仮想テーブルコピーを使用します。

コンパイラは、呼び出すAまたはBのTest()メソッドを呼び出さないため、C *を使用できません(CクラスはA::TestとB::Testの両方のシンボルを保持しているため)

C :: Test()メソッドを実装する場合、メソッドはAとBの両方に対して仮想であるため、A :: Test()とB :: Test()の代わりに両方が呼び出されます。

于 2012-06-28T09:35:39.080 に答える
0

Aの存在について何も知らないからですC

少し異なるシナリオを考えてみましょう。

foo.h

class A { public: virtual void Test() {} };

void myFunction(A *a);

foo.cpp

#include "foo.h"

void myFunction(A *a) {
    a->Test();
}

あなたはこれがコンパイルされることを期待するでしょう、私は推測しますか?しかし、後でAから独立して継承した場合、このコードがコンパイルされるかどうかに影響するのでしょうか。

于 2012-06-28T09:19:20.327 に答える