2015-07-10 2 views
5

sagen, dass ich die folgende Klasse haben: (möglicherweise meta-generated)Call a Klassen unter Verwendung eines std :: string

class MyClass 
{ 
    public: 
     myMethod(); 
    ... 
} 

hier ein paar Dinge Unter der Annahme:

1.) I have the class name from somewhere (let's pretend) 
2.) I have the names of the class methods somewhere (std::map< std::string, std::function> ... perhaps?) 

So ... Da ich den Namen myMethod() bis zur Laufzeit nicht kennen kann, gibt es eine Möglichkeit, es unter Verwendung einer std::string zu nennen? Dies setzt voraus, dass ich die Namen einer Klasse Funktionen irgendwo gespeichert habe.

MyClass example; 

std::string funcName{ findMyMethod() };//get std::string name of myMethod 

example.someHowRunMyMethodUsing_funcName_(); 

weiß ich C++ ist in der Regel nicht für Selbstbeobachtung ähnliche Situationen geeignet, aber ich möchte dies herauszufinden.

Danke!

+0

Haben die Methoden dieselbe Signatur? – Jarod42

+0

Viele verschiedene Signaturen, aber ich werde Zugriff auf ihre String-Namen haben. Es kann am Ende einige Namenskonventionen geben, um es einfacher zu machen. – DaveyLaser

+0

So scheint es, dass Sie mehrere Karten benötigen, eine nach Signatur. – Jarod42

Antwort

3

Es gibt viele Möglichkeiten, aber eine Karte von Mitgliedsfunktionszeiger verwendet, ist wahrscheinlich unter den allgemeinsten für Methoden mit derselben Signatur.

#include <iostream> 
#include <map> 
#include <string> 
using namespace std; 

class My_class 
{ 
public: 
    void method_1() { wcout << "method_1\n"; } 
    void method_2() { wcout << "method_2\n"; } 
    void method_3() { wcout << "method_3\n"; } 
}; 

auto method_name() -> string { return "method_3"; } 

auto main() -> int 
{ 
    map<string, void (My_class::*)()> methods = 
    { 
     { "method_1", &My_class::method_1 }, 
     { "method_2", &My_class::method_2 }, 
     { "method_3", &My_class::method_3 }, 
    }; 

    My_class example; 
    (example.*methods.at(method_name()))(); 
} 

Die Unterstützung unterschiedlicher Signaturen ist viel schwieriger.

Dann würden Sie im Wesentlichen in DIY-Laufzeittyp-Überprüfung sein.

1

Es gibt keine integrierte generische Möglichkeit, dies in C++ zu tun.

Das nächste, was Sie tun können, ist virtuelle Funktionen in C++ zu verwenden, um "späte Bindung" zu erreichen, aber in diesem Fall müssen Sie nur durch eine Menge von Reifen.

http://www.thegeekstuff.com/2013/06/cpp-virtual-functions/

Es ist nicht so flexibel wie "Call-by-Name", dass höhere Sprachen wie Ruby-Unterstützung.

In einem dynamischen Bibliothek/Modul Kontext haben Sie ein paar mehr Optionen Funktionen wie dlopen verwenden, aber diese sind leichter in C.

können http://linux.die.net/man/3/dlopen

4

Sie tun das, zu verwenden, wenn Sie map von std::string halten - >member function pointers.

std::map<std::string, void (MyClass::*)()> functionMap; 
functionMap["myMethod"] = &MyClass::myMethod; 

und später

// Get the function name from somewhere. 
std::string name = getFunctionName(); 

// Get the object from somewhere. 
MyClass* obj = getObject(); 

// Check whether there is a function corresponding to the function name. 
auto iter = functionMap.find(name); 
if (iter != functionMap.end()) 
{ 
    auto fun = iter->second; 
    (obj->*fun)(); 
} 
else 
{ 
    // Deal with missing function. 
} 
1

Es gibt COM IDispatch Schnittstelle, die genau die gleiche Funktionalität implementiert, so dass Sie Ihre eigenen Analogon dieser Schnittstelle erstellen und mit Ihrer Klasse verwenden können.

interface IMyDispatch 
{ 
public: 
    virtual bool Invoke(const std::string, void*) = 0; 
    virtual ~IMyDispatch() {}; 
}; 

///... 

class CSomeClass : public IMyDispatch 
{ 
public: 
    void DoSomeCoolStuff() { /*some cool stuff here*/ }; 
public: //IMyDispatch 
    bool Invoke(const std::string szName, void* pData) 
    { 
    if(szName == "DoSomeCoolStuff") //or methods map from the other ansvers 
    { 
     DoSomeCoolStuff(); 
     return(true); 
    } 

    return(false); 
    } 
} 

int main() 
{ 
    CSomeClass *pCl; 
    IMyDispatch* pDisp = dynamic_cast<IMyDispatch*>(pCl); 
    if(pDisp) 
    pDisp->Invoke("DoSomeCoolStuff", nullptr); 
} 
Verwandte Themen