2012-03-29 15 views
9

Ho bisogno di risolvere un problema del genere. Esiste una classe base e due classi ereditate. La classe base contiene un metodo che ha bisogno di un puntatore a funzione come parametro. Ma tali funzioni sono definite nelle classi ereditate.Puntatori funzione ed eredità

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 compilatore dà un errore sul WaitEvent chiama:

errore C2664: 'CBase :: WaitEvent': non può convertire il parametro 1 da 'bool (__thiscall CChildA :: *) (void) 'a' FPredicate '

Una domanda è: come devo cambiare il codice per farlo funzionare? sarà sicuro riscrivere la chiamata WaitEvent come WaitEvent((FPredicate)(&CChildA::a1), 100)?

In questo caso il compilatore non dice errori ma è sicuro? O c'è un modo migliore per risolvere un problema?

Grazie in anticipo.

+0

c'è qualche possibilità che tu possa usare boost o std :: tr1? In questo caso useresti semplicemente una funzione e nella classe derivata usi bind() con una funzione membro – stijn

+0

@stijn, ricorda, C++ 11 è live e 'bind()' dovrebbe già essere in 'std ::' . Ed è generalmente utile usare -std = C++ 0x, dato che alcune piccole funzionalità, che aiutano nella programmazione quotidiana, sono già utilizzabili. – Griwes

+0

È possibile rendere virtuali le funzioni callable nelle classi derivate dalla classe base? –

risposta

3

Il problema è che il passaggio implicito è diverso nel tipo. O lo lanci, ma questo probabilmente fallirà in presenza di ereditarietà multipla. Una migliore & soluzione più robusta sarebbe quella di cambiare la firma:

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

Grazie, penso che farò un cast come descritto nel mio primo post.A proposito, ho fatto alcuni test e stavano bene. Quindi, non essendoci più eredità, nessun problema dovrebbe verificarsi. –

3

è possibile farlo utilizzando una classe template per fare una chiusura del vostro oggetto figlio e dei suoi Stati funzione di risparmio è tipo corretto. E poi usando le funzioni virtuali per permettere alla classe base di chiamarlo attraverso il solito polimorfismo.

Un meccanismo simile viene utilizzato in shared_ptr per chiamare i distruttori. Vedi: 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; 
}