2010-12-03 8 views
5

次のコードを考慮してください。ファンクションポインタを使用して仮想関数を静的に呼び出す

#include <iostream> 
#include <memory> 

struct A { 
    A() {} 
    virtual void f() { 
    std::cout << "A::f" << std::endl; 
    } 
private: 
    A(const A&); 
}; 

struct B : public A { 
    virtual void f() { 
    std::cout << "B::f" << std::endl; 
    call(&A::f); 
    } 
private: 
    void call(void (A::*aMethod)()) { 
    // ... 
    (static_cast<A&>(*this).*aMethod)(); 
    //(static_cast<A>(*this).*aMethod)(); -> not allowed to copy! 
    // ... 
    } 
}; 

void main() { 
    std::auto_ptr<B> b (new B); 
    b->f(); 
} 

それはスタックを使い果たすまで、私はA::fを呼び出すcall方法をしたいと思いながら、このコードでは、再帰的に、同じB::fメソッドを呼び出します。つまり、通常、私は単純に書かれていた起こると、それは静的にそれを呼び出す必要があり、次のとおりです。

struct B : public A { 
    virtual void f() { 
    std::cout << "B::f" << std::endl; 
    // ... 
    A::f(); 
    // ... 
    } 
}; 

私はcallメソッドを持ちたい理由は共通である「静的呼び出し」の前と後にいくつかのコードを考慮することですfと同じシグネチャを持ついくつかの方法に...

は、どのように私は、静的実行時に決定した仮想関数を呼び出すことができますか?

+0

'B :: f'では、なぜ' call'と関数ポインタを通して関数を呼び出さなければなりませんか?どうしてあなたは 'A :: f();'を実行できませんか? (「前」と「後」のコードをいくつかの一般的な関数または共通のクラスにリファクタリングする) –

+0

これはおそらく私がしなければならないことです...メソッド 'call'はコードを取り除くためだけにありましたが、 –

答えて

4

これは期待しています。オブジェクト式はBaseクラスAへの参照であるため、A :: fが仮想であるため、仮想関数メカニズム(動的バインディング)がトリガされます。

のみ::演算子は、仮想関数呼び出しメカニズムをsupperessすることができます。

$ 10.3/12〜は、 " スコープ演算子(5.1)との明示的な資格が 仮想呼び出しメカニズムを抑制することができます。"

+0

...私は私がすることを目的として使用することはできません実現し、それは私がここにスコープ演算子を使用することはできません思わない:それはポインタの名前を修飾するだろう、ない機能がに指摘... –

+0

はい、AFAICT、あなたはA :: fとする必要があります:: f – Chubsdad

1

ポインタを取るときにオーバーライドが解決されるため、ここでは簡単にこのようにすることはできません。あなたの関数を呼び出すラッパーは、外部関数か関数を呼び出す非仮想関数のいずれかです。 C++ 0xの機能を持っているなら、最もクリーンなソリューションIMOであるラムダを使うことができます。

あなたは、あなたの問題に取り組むための別の方法として、プリ/ポスト機能を実行する方法を再考したいかもしれません:彼らは、過負荷をで実現することができる「 - >」演算子を。

+0

残念なことに、overloading operator->はfと他の同様のものだけでなく、呼ばれるメソッドに適用されるため、実際のケースでは適用されません...しかし、とにかくありがとう... –

+0

はい、それは通常問題です。しかし、あなたのコードをリファクタリングして、それらのメソッドだけを別のインターフェイスクラスに入れることもできます。または、仮想関数の呼び出しサイトでラップ演算子を適用するだけです。 Call(myObject) - > f(); – ltjax

+0

実際には、最後のアイデアのために、オーバーロードする必要はありません。 「コール」タイプのctorとdtorを実装するだけで十分です。 – ltjax

関連する問題