2012-03-29 28 views
9

このような問題を解決する必要があります。 基本クラスと2つの継承クラスがあります。基本クラスには、関数ポインタをパラメータとして必要とするメソッドが含まれています。しかし、そのような関数は継承クラスで定義されています。メンバ関数のポインタと継承

エラーC2664: 'にCBase :: WaitEventは':「ブール(__thiscall CChildA :: *)(空)からパラメータ1を変換することはできません

class CBase; 

typedef bool (CBase::*FPredicate)(); 

class CBase 
{ 
public: 
    CBase() {} 
    ~CBase() {} 
protected: 
    //this method waits until 'predicate' is true or until 'timeout' ms. passed 
    //and returns true if 'predicate' is true eventually 
    bool WaitEvent(FPredicate predicate, int timeout) 
    { 
     bool result = false; 
     int time1 = GetTickCount(); 
     int time2; 

     bool isEnd = false; 
     while(!isEnd) 
     { 
      result = isEnd = (this->*predicate)();    

      time2 = GetTickCount(); 
      if(time2 - time1 > timeout && !isEnd) 
       isEnd = true; 
     } 
     return result; 
    } 
}; 

class CChildA : public CBase 
{ 
protected: 
    bool a1() {/*some work*/} 
    bool a2() {/*some work*/} 
    void a_main() 
    { 
     ... 
     WaitEvent(&CChildA::a1, 100); 
     ... 
     WaitEvent(&CChildA::a2, 100); 
     ... 
    } 
}; 

class CChildB : public CBase 
{ 
protected: 
    bool b1() {/*some work*/} 
    bool b2() {/*some work*/} 
    void b_main() 
    { 
     ... 
     WaitEvent(&CChildB::b1, 100); 
     ... 
     WaitEvent(&CChildB::b2, 100); 
     ... 
    } 
}; 

MSVC 2005コンパイラはWaitEventにエラーが呼び出しています'〜' FPredicate '

質問はどうすればコードを変更して正常に動作させることができますか? WaitEventコールを WaitEvent((FPredicate)(&CChildA::a1), 100)と書き換えても安全ですか?

この場合、コンパイラはエラーを通知しますが、安全ですか?それとも、問題を解決する良い方法がありますか?

ありがとうございます。

+0

boostまたはstd :: tr1を使用できますか?その場合、関数を使用し、派生クラスではbind()をメンバ関数 – stijn

+0

@stijnで使用します。C++ 11はライブであり、 'bind()'はすでに 'std ::'にあります。 。そして、一般的には、-std = C++ 0xを使用することが有益です。これは、日々のプログラミングに役立つ小さな機能が既に使用可能であるためです。 – Griwes

+0

基本クラスの仮想派生クラスで呼び出し可能な関数を作成できますか? –

答えて

3

問題は暗黙的に渡されるという問題です。あなたがそれをキャストするか、複数の継承の存在下でおそらく失敗するでしょう。あなたはそれが正しいタイプだ保存あなたの子オブジェクトの閉鎖とそのメンバ関数を実行するために、テンプレートクラスを使用してそれを行うことができます

template< typename T > 
bool WaitEvent(bool (T::*predicate)(), int timeout) { ... } 
+0

ありがとう、私はちょうど私の最初の投稿に記載されているようにキャストをするだろうと思う。ところで、私はいくつかのテストを実行し、彼らは大丈夫だった。したがって、複数の継承は存在しないため、問題は発生しません。 –

3

:より良い&より堅牢なソリューションは、に署名を変更することです。仮想関数を使用して、基本クラスが通常の多態性によって呼び出すようにします。

同様のメカニズムが、デストラクタを呼び出すためにshared_ptrで使用されています。参照:http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stephan-T-Lavavej-Advanced-STL-1-of-n

#include <iostream> 

struct CPredicateBase 
{ 
     virtual ~CPredicateBase() {} 
     virtual bool operator()() = 0; 
}; 

template <class T> 
struct CPredicate : public CPredicateBase 
{ 
     bool (T::*func)(); 
     T* self; 

     CPredicate(T* self_, bool (T::*func_)()) 
     : func(func_), self(self_) {} 

     bool operator()() { return (self->*func)(); } 
}; 

class CBase 
{ 
public: 

     bool WaitEvent(CPredicateBase& predicate, int imeout) 
     { 
       /// just to show the call 
       bool b = predicate(); 
       std::cout << "WaitEvent called predicate() => " << b << std::endl; 
       return b; 
     } 
}; 


class CChildA : public CBase 
{ 
public: 
     bool a1() { return false; } 
     bool a2() { return true; } 

     void a_main() 
     { 
       std::cout << "CChildA::a_main()" << std::endl; 
       CPredicate<CChildA> caller1(this, &CChildA::a1); 
       bool ra1 = WaitEvent(caller1, 100); 
       CPredicate<CChildA> caller2(this, &CChildA::a2); 
       bool ra2 = WaitEvent(caller2, 100); 
     } 
}; 

class CChildB : public CBase 
{ 
public: 
     bool b1() { return false; } 
     bool b2() { return true; } 

     void b_main() 
     { 
       std::cout << "CChildB::b_main()" << std::endl; 
       CPredicate<CChildB> caller1(this, &CChildB::b1); 
       bool rb1 = WaitEvent(caller1, 100); 
       CPredicate<CChildB> caller2(this, &CChildB::b2); 
       bool rb2 = WaitEvent(caller2, 100); 
     } 
}; 

int main(int argc, char const* argv[]) 
{ 
     CChildA cA; 
     CChildB cB; 

     cA.a_main(); 
     cB.b_main(); 

     return 0; 
} 
関連する問題