2016-04-09 13 views
2

Wie weise ich Referenzen von nicht statischen Memberfunktionen mit identischen Signaturen, aber aus verschiedenen Klassen, einem Funktionszeiger mit einer passenden Signatur zu?C++ Zeiger auf eine Memberfunktion einer Klasse mit übereinstimmenden Funktionssignaturen

Ich kann dies mit Hilfe von std::function aus der C++ - Standardbibliothek tun. Ich mache das auch die ganze Zeit mit regulären C-Funktionen und ohne Hilfe von der Std-Bibliothek. Ich schreibe Firmware und Coderaum ist begrenzt. Wenn Helfer aus der C++ - Standardbibliothek dies tun können, muss es sicherlich möglich sein, dies manuell unter Verwendung von rein C/C++ - Sprachkonstrukten zu tun (vor C++ 11 bevorzugt).

Beispielcode meine Absicht demonstriert:

class A { 
public: 
    void ping_event_handler(); 
}; 

class B { 
public: 
    void ping_event_handler(); 
}; 

void A::ping_event_handler_A() { 
    // Handle ping event in A... 
} 

void B::ping_event_handler_B() { 
    // Handle ping event in B... 
} 

void ping_event_handler_C() { 
    // Handle ping event in normal function... 
} 

int main() { 

    // Ping event "pointer to a function that takes no arguments" 
    void (*ping_event)(); 

    A a(); 
    B b(); 

    ping_event = a.ping_event_handler; // Attach class A's handler 
    ping_event();      // Trigger event 

    ping_event = b.ping_event_handler; // Attach class B's handler 
    ping_event();      // Trigger event 

    ping_event = ping_event_handler; // Attach non-class handler 
    ping_event();      // Trigger event 

} 
+0

Für einen Start 'A a () "ist falsch. Dies deklariert eine Funktion 'a' –

+0

' ping_event = a.ping_event_handler; '- Woher weiß der Compiler, welchen Wert er 'this' geben soll? –

+0

Entweder deklarieren Sie diese Methoden als statisch (wenn sie den Status des Objekts nicht benötigen) oder virtuell (geerbt von einer gemeinsamen Basisklasse) und ersetzen den Zeiger auf eine Funktion durch einen Zeiger auf eine Basisklasse. Wenn Sie Zeiger auf Funktionen und Zeiger auf Methoden mischen wollen, dann benötigen Sie einen Wrapper als std: function. – avsmal

Antwort

1

Der alte Weg ist es, eine userData mit der Funktion

void (*ping_event)(void* userData); 

und sowohl die Funktion und speichern Userdata zu übergeben. dann in Anwenderseite, die Userdata darin Klasse Gießen und jede Methode von ihrem Aufruf:

struct my_function 
{ 
    my_function(void (*f)(void*), void* userData) : mF(f), mUserData(userData) 
    {} 

    void set(void (*f)(void*), void* userData) 
    { 
     mF = f; 
     mUserData = userData; 
    } 

    void operator()() { 
     mF(mUserData); 
    } 
    void (*mF)(void*); 
    void* mUserData; 
}; 

Und am Aufrufort:

template <typename C, void (C::*m)()> 
void my_func_helper(void* userData) 
{ 
    C* c = static_cast<C*>(userData); 
    (c->*m)(); 
} 


int main() 
{ 
    A a; 

    my_function f(&my_func_helper<A, &A::ping_event_handler>, &a); 

    f(); 

    B b; 

    f.set(&my_func_helper<B, &B::ping_event_handler>, &b); 
    f(); 

    f.set(ping_event_handler_c, NULL); 
    f(); 
} 

Demo

+0

Gut gemacht! Funktioniert perfekt und ohne Standardbibliothek oder Unterklasse. Könnten Sie möglicherweise einen Verweis darauf verwenden, wie ein Funktionsaufruf mit einem Argument aussehen würde? Oder ist das nicht möglich? –

+1

Sie müssen den Funktionszeigertyp ändern und den Funktionsaufruf ändern: [Demo] (http://coliru.stacked-crooked.com/a/2458b90c6fad2f52) – Jarod42