Nicht statische Funktion zu Funktionspointer

  • C++

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von Gonger96.

    Nicht statische Funktion zu Funktionspointer

    Ich bin ehrlich gesagt etwas schockiert. Wollte grad was kleines in C++ machen (performance gründe) und muss irgendwie feststellen, dass ich keinen Pointer auf eine nicht statische Methode bekomme.
    Ich lese überall, dass dies nicht möglich ist, manche kommen boost etc. daher (wobei ich ehrlich gesagt für sowas kleines kein boost verwenden will) und so weiter und so fort.
    Jetzt frage ich hier mal ganz konkret. Ist das wirklich nicht möglich? Wenn ja, dann finde ich das verdammt schwach von C++. Sollte nen Callback ner WinAPI übergeben und dieser Callback stellt keinen Context, UserData,... zur Verfügung. Somit bin ich ehrlich gesagt aufgeschmissen, denn wie komm ich so auf ne Instanz einer Klasse?


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Was möchtest du genau machen ?

    Erstmal gibts zwei Arten von Funktionszeigern einmal statische/nonMember void (*) () und Memberfunktionen void(Klasse::*) (). Das liegt daran, dass Memberfunktionen implizit der this-Zeiger übergeben wird, damit diese auf ihre Klasse zugreifen können und so haben die als Callingconvention __thiscall. Man kommt aber natürlich auch an Memberfunktionen per Klasse::Funktion und ruft diese dann per (Klassen_Zeiger->*Funktion_Zeiger)(Argumente) auf. Bei API's wird meistens __stdcall gefordert um welche geht es denn ? Bei den meisten kann man da n LPARAM reingeben, falls nicht gibts da keine Möglichkeit.

    Edit:
    Hier mal ein Beispiel
    Spoiler anzeigen

    C-Quellcode

    1. class xy
    2. {
    3. public:
    4. void test(int i) {cout << i << endl;};
    5. };
    6. void call_xy_func(void(xy::*func_ptr)(int), xy* class_ptr, int arg)
    7. {
    8. (class_ptr->*func_ptr)(arg);
    9. }
    10. int main(int argc, char* argv[])
    11. {
    12. xy inst;
    13. call_xy_func(&xy::test, &inst, 6);
    14. return 0;
    15. }

    Btw. als Template
    Spoiler anzeigen

    C-Quellcode

    1. class xy
    2. {
    3. public:
    4. void test(int i) {cout << i << endl;};
    5. };
    6. template <typename _cl, typename... _args>
    7. void call_func(void(_cl::*func_ptr)(_args...), _cl* class_ptr, const _args&... args)
    8. {
    9. (class_ptr->*func_ptr)(args...);
    10. }
    11. int main(int argc, char* argv[])
    12. {
    13. xy inst;
    14. call_func(&xy::test, &inst, 9);
    15. return 0;
    16. }

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Gonger96“ ()

    Das Problem ist, die verkackte WinAPI (wie immer). Das ist von dem her schon mal kein __thiscall, da das CALLBACK Makro ja für __stdcall steht.
    Das heißt es ein nonMember Callback. Jetzt will ich aber unbedingt, das auf eine Instanz bringen. Und das muss doch auch irgendwie möglich sein oder nicht?

    std::bind und std::function habe ich jetzt schon öfters gelesen. Jedoch ist dort nirgends wirklich beschrieben inwiefern man das nun produktiv zur Lösung des Problems einsetzt. Gibt es da irgendwo ein Beispiel wie ich eine memberFunktion in eine nonMemberFunktion bringe?


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Morgen ^^
    std::bind und function haben damit garnichts zutun. Bind bindet Argumente an Funktionen, ist ne geniale Funktion und function ist n Delegate. Die WinAPI ist komplett in C, deswegen ist das jedesmal ein Akt sowas in C++ "schön" zu benutzen. Um welche Funktion handelt es sich denn ?

    Ich seh keine Möglichkeit eine Instanz mitzugeben ohne LPARAM/UserData Parameter. Normalerweise ist sowas immer dabei. Sonst würden Win32 Wrapper wie WinForms (WPF ja auch teils) garnicht funktionieren.
    Es handelt sich um die SetWindowsHookEx Funktion. Sehe keine Möglichkeit da UserData oder sowas mitzugeben.
    Was a) ein enormer Dreck seitens WinAPI ist, jedoch b) finde ich das auch recht schwach von C++, dass es da keine Möglichkeit gibt.
    Was also würdest du vorschlagen?
    Ich könnte theoretisch mehrere Instanzen erlauben, jedoch intern immer den selben Hook verwenden. Wenn alle Instanzen gestoppt sind, dann wird auch der Hook gestoppt. Und der Hook verwendet dann halt eine statische Funktion welche quasi Broadcast mäßig an alle anderen Instanzen weitergeht.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    b) ist Quatsch. thiscall ist kein stdcall, ich kann ja auch nicht aus ner statischen Funktion auf Klassenmember zugreifen. Ich kann ja nicht einfach so einen Parameter weglassen. Wie gesagt eine thiscall-Methode wird in der PE einmal abgelegt und zwar mit dem zusätzlichen Parameter (dem this-Zeiger). Die Methode wird dann von allen Klasseninstanzen aufgerufen, die geben nur ihren Klassenzeiger mit rein und die Funktion kann auf die Klasse zugreifen.
    a) Trifft absolut zu. Die ganze WinAPI ist verbaut bis zum Gehtnichtmehr.

    Erklär mal ganz genau was du machen willst und auf welche Klassen du warum zugreifen willst. Vielleicht kann man da was drehen. Notfalls macht man musst du die statisch machen und jede Klasseninstanz durchklappern.
    Ich habe einfach nur eine Klasse welche einen Hook starten kann und intern halt auch von diesem benachrichtigt werden soll.
    Was jedoch b) angeht: Das sehe ich sehr wohl auch irgendwo so. Mir leuchtet natürlich ein weshalb es nicht geht. Jedoch wenn ich das sogar in C# über Interops machen kann, dann müsste es doch erst recht eine Möglichkeit in C++ dazu geben.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    C# ist ja auch verwaltet, C++ nicht. Marshal generiert da irgendwie ne neue Funktion und bindet den Zeiger, weiß garnicht so genau wie dass verwaltet wird. In C++ geht's auch, ich kann Problemlos aus function<void(Klasse*, int)> per binder function<void(int)> oder function<void()> machen. Das Problem ist hier aber C. C kennt keine modernen Delegates sondern nur Funktionszeiger, dass Problem ist jetzt eigentlich nur die Instanz irgendwo her zu bekommen. Den Hook würde ich aber sowieso statisch machen, sonst hooked man ja bei jeder Instanz. Ich würds einfach so aufbauen:

    C-Quellcode

    1. class hook_class
    2. {
    3. public:
    4. hook_class() {global_instances.push_back(this);};
    5. hook_class(const hook_class&) {global_instances.push_back(this);};
    6. ~hook_class() {global_instances.remove(this);};
    7. private:
    8. static list<hook_class*> global_instances;
    9. static LRESULT __stdcall hook_proc(int i, LPARAM lParam, WPARAM wParam)
    10. {
    11. for(auto& inst : global_instances)
    12. inst->member_hook_proc(i, lParam, wParam);
    13. return 0;
    14. };
    15. void member_hook_proc(int, LPARAM, WPARAM) {};
    16. };
    Ja so hätte ich das eben gedacht gehabt. Und nö. C++ kann es nicht und C# kann es. C# kommt auch mit deinen sogenannten "C Funktionszeigern" zurecht.
    Außerdem C# veraltet?(Lesen will gelernt sein) Naja. Lassen wir das Thema. Beide Sprachen haben ihre Vor- und Nachteile. Jedoch sehe ich das als klaren Nachteil.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.

    thefiloe schrieb:

    Ja so hätte ich das eben gedacht gehabt. Und nö. C++ kann es nicht und C# kann es. C# kommt auch mit deinen sogenannten "C Funktionszeigern" zurecht.
    Außerdem C# veraltet? Naja. Lassen wir das Thema. Beide Sprachen haben ihre Vor- und Nachteile. Jedoch sehe ich das als klaren Nachteil.


    C# ist ja auch verwaltet, C++ nicht
    Verwaltet nicht veraltet. Ist ja wohl alles andere als veraltet :D
    C++ kommt auch mit Funktionszeigern klar, ist ja immernoch eine Weiterentwicklung von C. Nur ich wüsste nicht wie es Möglich sein sollte von thiscall nach stdcall zu kommen ohne binder, ausserdem ist dass ja auch Schwachsinn. Das ist kein Nachteil es ist schlicht nicht möglich. Die Einzig gute Lösung ist einfach sowas mit in die "UserData" zu packen, falls es die nicht gibt hat MS wohl nicht vorgesehen diese Funktion so zu nutzen, also soll nur einmal pro Prozess gehooked werden, was bei nem Blick auf die Parameter ja auch klar wird. Also solltest du deine Archiktektur anpassen