Zeiger auf Methoden
-
Hallo, ich habe ein sehr seltsames Problem. Zuerst etwas Code:
class MenuButton : public Button { public: MenuButton( const D3DXVECTOR3& location, const std::wstring& caption, void (*actionMethod)() ); virtual void draw(unsigned int alpha) const; virtual void click(); private: void (*actionMethod)(); const std::wstring caption; };Später erzeuge ich Instanzen dieser Klasse und pushe Zeiger darauf in einen vector:
[...] std::vector<controls::Control* const> elements; elements.push_back( new MenuButton( D3DXVECTOR3(362.0f, 280.0f, 0), L"blabla", NULL ) ); elements.push_back( new MenuButton( D3DXVECTOR3(362.0f, 400.0f, 0), L"blabla", NULL ) ); [...]So. Eigentlich brauche ich aber in der Klasse MenuButton Zeiger auf nicht-statische Methoden.
Ich ändere also die Klasse wie folgt:class MenuButton : public Button { public: MenuButton( const D3DXVECTOR3& location, const std::wstring& caption, void (Menu::*actionMethod)() ); virtual void draw(unsigned int alpha) const; virtual void click(); private: void (Menu::*actionMethod)(); const std::wstring caption; };Und jetzt gibt es beim push_back des Vectors einen Fehler. Manchmal acces violation, wenn ich die Ordnung ein bisschen ändere, kommt manchmal bad_alloc mit warning ich hab versucht, mehr als 0x7ffeff auf einmal zu allokieren (das geschieht in der Methode push_back!).

Mir ist der Zusammenhang nicht klar. Sind die Methodenzeiger nicht ok? Warum geht ausgerechnet das pushen nicht? Warum soll das pushen eines billigen Zeigers nicht gehen?
Wenn ich die Zeiger auf statische Methoden lasse, funktioniert alles!
-
Ok... also ich bin gerade zufällig auf etwas ziemlich witzloses gestoßen. Wenn ich die Klassendefinition von Menu include, funktioniert alles.
Wenn ich sie nicht include (in diesem Fall habe ich nur eine forward-Deklaration), kriege ich besagtes Problem.Ich weiß nicht, warum der Compiler die Defintion für Menu braucht, wenn er nur void (Menu::*actionMethod)(); fressen muss. Ich weiß nicht, warum er dann nicht wenigstens jammert. Ich weiß auch nicht, warum er ausgerechnet bei std::vector::push_back dann abbricht.
Aber vielleicht will ich es ja auch gar nicht wissen.Das Problem ist auf jeden Fall erledigt.
-
einfache antwort:
void (Menu::*actionMethod)();das ding kann unterschiedlich groß sein, zwischen 4 und X Byte-ist compiler und situationsabhängig. Bei manchen ist die Größe Konstant, dh ein zeiger auf die vtable, und ein offset, andere legen für jede vererbung einen eigenen zeiger auf die entsprechende vtable an. Methodpointer sind wegen der multiple inheritance so krumm und schief. kann man nichts machen.
Bei vielen compilern macht das absolut keine probleme, die benutzen dann einen defaultzeiger, der die maximale byte anzahl verbraucht-man kann ja nie wissen.
manche compiler können das aber nicht.Es wird wohl am besten sein, du akzeptierst funktoren, dann sieht die welt glatt wieder etwas schöner aus.
-
Da die Methoden nicht virtuell sind, sehe ich in diesem Fall eigentlich kein konkretes Problem. Ich habe auch kein Problem damit, dass er die Klassendefinition von Menu will, aber dass er einfach Mist macht, anstatt die Definition zu verlangen, erstaunt mich ein wenig.
-
Hi,
inwiefern ist es denn bei einem Zeiger wichtig, wie groß das ist, worauf er zeigt, otze?
MfG Eisflamme
-
die größe der Klasse ist unwichtig. Das einzige was wichtig ist, ist die tiefe der Vererbungshierarchie, weil sich damit die methodpointer ändern, und das unabhängig davon, ob die methode auf die der methodpointer zeigt virtual ist, oder nicht.
//edit nur zur verdeutlichung des problems:
struct Base{ virtual void foo()=0; void bar(){} }; struct Derived{ void foo(){} }; typedef void(Base::*)() mp; //in der main Base* a=new Derived; mp b=&foo; mp c=&bar; (a.*b)(); (a.*c)();das compiled, aber da foo im gegensatz zu bar virtual ist, muss sich der methodpointer anders verhalten,dh er braucht die vtable. würden b und c aber unterschiedlich groß sein, könnte man sie nicht in einen vector packen, dh beide müssen gleich groß sein, und somit muss c sich der größe von b anpassen, die natürlich bekannt sein muss(bzw sollte, der standard erlaubt es auch, wies optimizer genutzt hat).
hier ein text dazu:
http://www.codeproject.com/cpp/FastDelegate.aspein kurzer abschnitt:
There's another interesting rule in the standard: you can declare a member function pointer before the class has been defined. This has some unexpected side-effects on some compilers, which I'll discuss later. It's better to avoid this if you can.