3

私は自分のプロジェクトで関数ポインターを使用していますが、問題に直面しており、それを示すテストケースを作成しています...以下のコードは、MSVC2005 で以下のエラーで失敗します (簡単に言えば、基本クラス関数ポインターを介して派生クラス関数にアクセスしたい)

エラー C2440: '=': 'void (__thiscall ClassB::* )(void)' から 'ClassAFoo' に変換できません

class ClassA {
 public: 
    virtual void foo() 
    {
       printf("Foo Parent"); 
    }
};

typedef void (ClassA::*ClassAFoo)();

class ClassB : public ClassA {
 public:
    virtual void foo() 
    { 
        printf("Foo Derived"); 
    }
};

int main() {
    ClassAFoo fPtr;
    fPtr = &ClassB::foo;
}

私の質問は

  1. 基本クラスの関数ポインタを介して派生クラス関数にアクセスできないのは C++ の動作ですか、それともコンパイラのバグですか?
  2. 上記のケースで遊んでいます。コメントアウトするClassB::fooと、このコードはそれ以上変更せずに正常にコンパイルされます。なぜそうなのか、fPtr = &ClassB::foo;再びコンパイル時エラーが発生することはありませんか?
4

3 に答える 3

5
  1. 正しい振る舞いです。のすべてのインスタンスには member がありますが、すべてのインスタンスにClassBmemberClassA::fooがあるわけではありません。実際にインスタンスの基本クラスのサブオブジェクトであるインスタンスだけがそれを持っています。したがって、「純粋な」オブジェクトに割り当ててから組み合わせて使用​​すると、存在しない関数を呼び出そうとします。ClassAClassB::fooClassAClassBClassB::fooClassAFooClassAFooClassA

  2. fooから削除するClassBと、式は実際に継承されたものをClassB::foo参照するので、問題はありません。ClassA::fooClassB

1. さらに詳しく説明すると、メンバーへのポインターは、実際には通常のポインターとは逆の方法で機能します。通常のポインターを使用すると、に代入できますがClassB*(ClassA*のすべてのインスタンスは のインスタンスでClassBもあるためClassA)、その逆はできません。メンバー ポインターを使用すると、 ( のすべてのメンバーが含まれているため) に代入できますが、ClassA::*その逆ClassB::*はできません。ClassBClassA

于 2013-04-12T12:14:56.383 に答える
3

はい、大丈夫です。class Aの関数ポインタの関数ポインタには代入できませんclass B。あなたはこれを行うことができます

fPtr = &ClassA::foo;
ClassB b;
classA* a = &b;
(a->*fPtr)();

オーバーライドされたClassB関数が呼び出されます。

に関数がない場合fooは、 のClassB関数ClassAが使用されます。実際の例

于 2013-04-12T12:14:50.013 に答える