Klasseninstanz und unsichtbare Parameter?
-
Halli hallo,
ich habe eine Frage bzgl. der WinAPI:
Ich übergebe einer Klasse einen Pointer auf eine Methode, welche aus einer anderen Klasseninstanz und nicht static ist. Vor der Übergabe caste ich die void Methode zum Typ "EVENT", dieser Typ schaut wie folgt aus:
typedef void (*EVENT)(void*, UINT ID);
EVENT nimmt also einen void* und einen unsigned int an.
Der void* enthält später die Klasseninstanz und ID enthält die ID des Objektes, von welchem die Methode/das Event aufgerufen wurde.Jetzt zu meiner Frage:
Wenn ich den Funktionspointer später in der anderen Klasse aufrufe, übergebe ich dem EVENT als void* die Klasseninstanz und als UINT die ID, die Methode, die dann über den Pointer aufgerufen wird, nimmt aber in wirklichkeit nur den unsigned int an, jedoch nicht den void*. Dennoch wird die Methode 100% korrekt ausgeführt, was mich verwirrt, da C++ lediglich den Pointer auf die Instanz als Übergabeparameter hat, mit dem ich aber rein garnichts mache, als ihn nur zu übergeben.
Ich habe alles extra in ein kleines Beispielprogramm verfrachtet, weil das Originalprojekt zu riesig ist um den Code hier zu posten:
#include <iostream> typedef void (*EVENT)(void*, int ID); using namespace std; class A { private: EVENT func; void* inst; int ID; public: A() { ID = 2734; }; ~A(){}; void setTarget(void* _inst) { inst = _inst; } void setEvent(EVENT _func) { func = _func; } void doEvent() { func(inst, ID); } }; class B { public: B(A* _inst_A) { cout<<"Klasse B Adresse: "<<this<<endl; _inst_A->setTarget(this); _inst_A->setEvent((EVENT)&B::testMethode); }; ~B(){}; void testMethode(int ID) { cout<<"In "<<this<<": "<<ID<<endl; } }; A inst_A; B inst_B(&inst_A); int main() { inst_A.doEvent(); return 0; }
Wie man sieht, wird in A::doEvent() das Event B::testMethode(int ID) ausgelöst (welches dann bei der Ausgabe die richtige Adresse zeigt) jedoch ohne mit dem Instanzzeiger auf inst_B irgendetwas zu machen.
Der Compiler gibt eine Warnung aus, da eben eine nicht-statische Methode ohne Referenz auf die Instanz übergeben wird und somit der Bezug verloren gehen könnte, was aber anscheinend nicht der Fall ist.
Kann es also sein, dass C++ im Hintergrund was mit diesem Pointer anfangen kann und ist es überhaupt ok soetwas zu machen?
Ich hoffe jemand nimmt sich diesen Post zu herzen und kann mir das eklären
Mfg.
[EDIT]
Mir ist gerade aufgefallen, dass das Problem an sich garnichts mehr mit der WinAPI zu tun hat (lediglich das Originalprojekt, aber das sieht man hier ja nicht). Falls der Post hier also stört, bitte verschieben, danke
-
Was du machst funktioniert, weil es halt mit deinem Compiler+Settings+Mondphase funktioniert.
Wenn man weiss wie Funktionsaufrufe so ca. gehen ist es nicht gerade SEHR verwunderlich dass es geht. Garantiertes Verhalten ist es trotzden nicht.Vom C++ Standard aus gesehen ist es auf jeden Fall UB.
Fix:
void B_testMethode_Trampolin(void* b, int ID); class B { public: B(A* _inst_A) { cout<<"Klasse B Adresse: "<<this<<endl; _inst_A->setTarget(this); _inst_A->setEvent(B_testMethode_Trampolin); // kein Cast mehr nötig }; ~B(){}; void testMethode(int ID) { cout<<"In "<<this<<": "<<ID<<endl; } }; void B_testMethode_Trampolin(void* b, int ID) { static_cast<B*>(b)->testMethode(ID); }
-
Danke für die Antwort + Fix, doch was bedeutet UB?
-
0xBAADF00D schrieb:
UB?
Undefined Behavior.
-
Du solltest Dich mal mit den verschiedenen Aufrufvarianten von Member-Methoden auseinander setzen... wenn es sich noch um virtuelle Methoden handelt, dann braucht man bis zu *16* Bytes um zu erkennen, welche Methode nuin in wirklichkeit aufgerufen werden soll!
Siehe auch:
http://msdn.microsoft.com/en-us/library/yad46a6zIrgendwo auf Codeproject gab es auch mal einen Artikel, der dies für den MS Compiler genau erklärt... aber wie schon gesagt, das ganze ist Compiler-Spezifisch und kein Standard...