2009-03-10 9 views
8

Me gustaría asignar una cadena a las funciones de un miembro de instancia y almacenar cada asignación en el mapa.Guardar punteros a la función de miembro en el mapa

¿Cuál es la forma limpia de hacer algo como eso?

class MyClass 
{ 
    //........ 
    virtual double GetX(); 
    virtual double GetSomethingElse(); 
    virtual double GetT(); 
    virtual double GetRR(); 
    //........ 
}; 


class Processor 
{ 
private: 
     typedef double (MyClass::*MemFuncGetter)(); 
     static map<std::string, MemFuncGetter> descrToFuncMap; 

public: 
     static void Initialize(); 
     void Process(Myclass m, string); 
}; 

void Processor::Initialize() 
{ 

    descrToFuncMap["X"]=&MyClass::GetX; 
    descrToFuncMap["SomethingElse"]=&MyClass::GetSomethingElse; 
    descrToFuncMap["RR"]=&MyClass::GetRR; 
    descrToFuncMap["T"]=&MyClass::GetT; 
}; 
void Processor::Process(MyClass ms, const std::string& key) 
{ 
    map<std::string, Getter>::iterator found=descrToFuncMap.find(key); 
    if(found!=descrToFuncMap.end()) 
    { 
     MemFuncGetter memFunc=found->second; 
     double dResult=(ms).*memFunc();  
     std::cout<<"Command="<<key<<", and result="<<result<<std::end;  
     } 
} 

avísame si ves un problema con este enfoque y cuáles son los modismos comunes para eso?

Tal vez, debería usar si-else-if cadena de declaración, dado que tengo un número limitado de funciones miembro, en lugar de un mapa confuso de punteros func

Por cierto, he encontrado algunos de los útiles información aquí, en el c++-faq-lite

+0

En realidad, creo que el mapa es más bonito que una cadena if-else. Le da un buen gancho para almacenar otra metainformación más adelante si surge la necesidad: simplemente expanda el tipo de valor del puntero a una estructura que contenga un puntero a la función más cualquier otra información que necesite. –

+0

Acepto, se ve mejor, aunque es más difícil de entender para un desarrollador menos experimentado. –

Respuesta

6

Me parece bien, pero por el hecho de que descrToFuncMap debe declararse static si desea inicializarlo desde la función estática Initialize().

Si desea asegurarse de que se llama Initialize(), y se llama solo una vez, puede utilizar el patrón Singleton. Básicamente, si no está haciendo multihilo, eso solo significa incluir descrToFuncMap dentro de su propia clase (llamada decir FuncMap) con un constructor privado que llame al Initialize(). A continuación, agrega una variable local static de tipo FuncMap a Processor::Process() - porque la variable es static, persiste y solo se inicializa una vez.

Ejemplo de código (ahora me doy cuenta de que friend no es realmente necesario en este caso):

class Processor { 
private: 
    typedef double (MyClass::*MemFuncGetter)(); 

    class FuncMap { 
    public: 
     FuncMap() { 
      descrToFuncMap["X"]=&MyClass::GetX; 
      descrToFuncMap["SomethingElse"]=&MyClass::GetSomethingElse; 
      descrToFuncMap["RR"]=&MyClass::GetRR; 
      descrToFuncMap["T"]=&MyClass::GetT; 
     } 

     // Of course you could encapsulate this, but its hardly worth 
     // the bother since the whole class is private anyway. 
     map<std::string, MemFuncGetter> descrToFuncMap; 
    }; 

public: 
    void Process(Myclass m, string); 
}; 

void Processor::Process(MyClass ms, const std::string& key) { 
    static FuncMap fm;  // Only gets initialised on first call 
    map<std::string, Getter>::iterator found=fm.descrToFuncMap.find(key); 
    if(found!=fm.descrToFuncMap.end()) { 
     MemFuncGetter memFunc=found->second; 
     double dResult=(ms).*memFunc();  
     std::cout<<"Command="<<key<<", and result="<<result<<std::end;  
    } 
} 

Este no es el "verdadero" patrón Singleton como diferentes funciones podría crear sus propias instancias separadas de FuncMap, pero es suficiente para lo que necesitas Para Singleton "verdadero", declararía privado el constructor FuncMap y agregaría un método estático, digamos getInstance(), que definió la instancia única como una variable static y devolvió una referencia a eso. Processor::Process() entonces usar esto con

FuncMap& fm = FuncMap::getInstance(); 
+0

sí, es estático (lo fijo). Me gusta la idea de una clase privada de amigos. ¿Lo demostrarías con un ejemplo? Gracias –

0

que cambiaría

void Processor::Process(MyClass ms, std::string key) 

a

void Processor::Process(const MyClass& ms, const std::string& key) 

No veo ningún efecto secundario malo por ahora. Probablemente con la función boost :: como valor de mapa, será más fácil en el futuro.

+0

, sí, sí, obviamente, pasaría cadena como una constante para referenciar. Mi pregunta es, quizás, debería usar la cadena if-statement dado que tengo un número limitado de funciones miembro en lugar de un mapa confuso de punteros func –

+0

Los mapas están bien para mí. –

0

Evitar el uso de 'virtual' si está utilizando mapas de punteros de función. En este contexto, usar la palabra clave 'virtual' no ayudará mucho. Por ejemplo

descrToFuncMap["X"]=&MyClass::GetX; 

siempre llamar 'MyClass :: GetX' de función, incluso si GetX queda anulado por la clase derivada de MiClase.

Por lo general, no tendrá una gran cantidad de funciones en la clase, en lugar de usar el mapa, puede crear una matriz de estructuras simple y usar un ciclo for.Si el número de funciones es pequeño, no habrá una gran diferencia de rendimiento en el mapa y la matriz. Algo similar al código siguiente funcionará

class MyClass 
{ 
    //........ 
    double GetX(); 
    double GetSomethingElse(); 
    double GetT(); 
    double GetRR(); 
    //........ 
}; 

typedef double (MyClass::*MemFuncGetter)(); 

struct FuncTable 
{ 
    const char* m_pFuncName; 
    MemFuncGetter m_pFuncPtr; 
}; 

class Processor 
{   
public: 
     void Process(Myclass& m, string); 
}; 

static FuncTable descrToFuncMap[] 
{ 
    { "X", &MyClass::GetX}, 
    { "SomethingElse", &MyClass::GetSomethingElse }, 
    { "RR", &MyClass::GetRR}, 
    { "T", &MyClass::GetT} 
}; 

void Processor::Process(MyClass& ms, const std::string& key) 
{ 
    int functablesize = sizeof(descrToFuncMap)/sizeof(descrToFuncMap[0]) 

    for(int i=0; i< functablesize; ++i) 
    { 
     if(strcmp(key.c_str(), descrToFuncMap[i].m_pFuncName)==0) 
     { 
      MemFuncGetter memFunc=descrToFuncMap[i].m_pFuncPtr; 
      double dResult=(ms).*memFunc();  
      std::cout<<"Command="<<key<<"result="<<result<<std::end; 
      break; 
     } 
    }  
} 
+0

¿Por qué no llama a una función anulada? –

Cuestiones relacionadas