2012-03-29 4 views
9

이러한 문제를 해결해야합니다. 기본 클래스와 두 개의 상속 된 클래스가 있습니다. 기본 클래스는 함수 포인터를 매개 변수로 필요로하는 메서드를 포함합니다. 그러나 이러한 함수는 상속 된 클래스에서 정의됩니다.멤버 함수 포인터 및 상속

오류 C2664 : 'CBase ::는 waitEvent'

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에 오류가 호출을 제공 부울 '에서 매개 변수 1 변환 할 수 없습니다 (__thiscall CChildA :: *) (무효) 'to'FPredicate '

질문 : 어떻게 작동 시키려면 코드를 변경해야합니까? WaitEvent 호출을 WaitEvent((FPredicate)(&CChildA::a1), 100)으로 다시 쓰는 것이 안전할까요?

이 경우 컴파일러는 오류는 표시하지 않지만 안전합니까? 아니면 문제를 푸는 더 좋은 방법이 있습니까?

미리 감사드립니다.

+0

부스트 또는 std :: tr1을 사용할 수 있습니까? 이 경우 함수 을 사용하고 파생 클래스에서는 member 함수 – stijn

+0

@stijn을 사용하여 bind()를 사용합니다. 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; 
}