2012-03-29 19 views
9

Necesito resolver ese problema. Hay una clase base y dos clases heredadas. La clase base contiene un método que necesita un puntero a función como parámetro. Pero tales funciones se definen en clases heredadas.Indicadores de función de miembro y herencia

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 compilador da un error en WaitEvent llama: C2664

error: 'CBase :: WaitEvent': no ​​se puede convertir el parámetro 1 de 'bool (__thiscall CChildA :: *) (void) 'para' FPredicar '

Una pregunta es: ¿cómo debo cambiar el código para que funcione? ¿Será seguro volver a escribir la llamada de WaitEvent como WaitEvent((FPredicate)(&CChildA::a1), 100)?

En este caso, el compilador no indica ningún error, pero ¿es seguro? ¿O hay una mejor manera de resolver un problema?

Gracias de antemano.

+0

¿hay alguna posibilidad de que pueda usar boost o std :: tr1? En ese caso, simplemente usaría una función y en la clase derivada use bind() con una función miembro – stijn

+0

@stijn, recuerde, C++ 11 está activo y 'bind()' ya debería estar en 'std ::' . Y generalmente es beneficioso usar -std = C++ 0x, ya que algunas pequeñas características, que ayudan en la programación diaria, ya se pueden usar. – Griwes

+0

¿Puede hacer que las funciones invocables en las clases derivadas sean virtuales desde la clase base? –

Respuesta

3

El problema es que el tipo implícitamente pasado esto difiere. O lo lanzas, pero probablemente fallará en presencia de herencia múltiple. Una mejor & solución más robusta sería cambiar la firma a:

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

Gracias, creo que haré un cast como se describe en mi primera publicación.Por cierto, realicé algunas pruebas y estuvieron bien. Entonces, como no habrá herencia múltiple, no debería haber problemas. –

3

usted puede hacerlo utilizando una clase de plantilla que hacer un cierre de su objeto hijo y su miembro de la función de ahorro es el tipo correcto. Y luego usar funciones virtuales para permitir que la clase base lo llame a través del polimorfismo habitual.

Un mecanismo similar se utiliza en shared_ptr para llamar a destructores. Ver: 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; 
} 
Cuestiones relacionadas