2

以下の例では、問題を最小限に抑えようとしましたが、A、B、C、D の 4 つのクラスがあります。、継承階層を形成します

プログラムが起動すると、クラスDのオブジェクト dが作成され、 Dクラスのテストメソッドが呼び出されます。このメソッドは、Cクラスの呼び出し元メソッドを呼び出します。このメソッドは、メンバ関数ポインタを使用して正しいfメソッドを呼び出そうとします。この場合、クラスDに関連付けられたfメソッドを呼び出す必要がありますが、クラスBに関連付けられたメソッドを呼び出します。

どうして ?

class A {
    public:
    virtual void f() = 0;
};

class B : public A{
    public:
    virtual void f() { cout << "IN B" << endl;}   
};

class C : public B{
    public:
    virtual void f() { B::f(); cout << "IN C" << endl; }
    virtual void caller(){
        void (A::*cb)() = NULL;
        cb = &A::f;
        (this->*cb)();
    }
};

class D : public C{
    public:
    virtual void f() { C::f(); cout << "IN D" << endl; }
    void test(){
         caller();
    }
};

int main(){
    D d;
    d.test(); // Why does this prints only "IN B" 
    return 0;
}

更新:コードは実際に機能します。問題は提示されたコードに起因するものではなく、クラス A、B、C を提供するライブラリとクラス D を提供するライブラリとの間のバージョンの不一致に起因するようです。

4

3 に答える 3

2

「INB」だけを印刷しますか?私はそれをMSVC2012でコンパイルしました、私は得ました

IN B
IN C
IN D

publicさらに、少なくともすべてのクラスに:を追加する前は、元のコードはVS2012でコンパイルされません。例えば:

class C : public B{
public:  // <--- here
    virtual void f() { B::f(); cout << "IN C" << endl; }
    virtual void caller(){
        void (A::*cb)() = NULL;
        cb = &A::f;
        (this->*cb)();
    }
};
于 2013-03-20T20:45:20.617 に答える
0

できます。public:宣言を追加します。オーバーロードと仮想化の異なる動作についても警告します。最善の方法は、ポインターまたは参照を使用することです。

class A {
public:
    virtual void f() = 0;
};

class B : public A{
    public:
    virtual void f() { std::cout << "IN B" << std::endl;}   
};

class C : public B{
    public:
    virtual void f() { B::f(); std::cout << "IN C" << std::endl; }
    virtual void caller(){
        void (A::*cb)() = NULL;
        cb = &A::f;
        (this->*cb)();
    }
};

class D : public C{
    public:
    virtual void f() { C::f(); std::cout << "IN D" << std::endl; }
    void test(){
         caller();
    }
};

出力:

イン B
イン C
イン D

于 2013-03-20T20:54:29.753 に答える
0

印刷します

IN B
IN C
IN D

というわけで、問題は別の場所にあります。

于 2013-03-20T20:43:05.733 に答える