Vermutlich ganz banales Problem mit RTTI
-
Guten Tag alle zusammen
Ich tue mich gerade ein wenig schwer mit der RTTI. Wieso ist die Ausgabe des folgenden Codes "class A" und nicht "class B"? Soviel ich weis, funktioniert die RTTI nur dann, wenn die entsprechende Klasse mindestens einmal abgeleitet wurde und die Basisklasse mindestens eine virtuelle Funktion besitzt. Beide Bedingungen sind doch in dem folgenden Fall erfüllt?#include <iostream> class A{ public: A(void){std::cout << typeid(*this).name() << std::endl;} virtual ~A(void){} }; class B:A{ }; void main(){ B b; }Ausgabe: "class A"

Vielen Dank im Vorraus!

-
Wenn ich mich richtig erinnere, wird zuerst der A Teil, und dann der B Teil konstruiert.
Im A Konstruktor existiert folglich nur ein A, nicht aber ein B Object (virtuelle Funktionsaufrufe rufen folglich auch die Funktion in A und nicht in B auf).Bei der Destruktion ist es genau anders herum, erst wird B, dann A zerstört.
Ich kann mich aber auch irren...
-
Das ist erst nach Ende des Kunstruktors so ein Ding. Vorher wär's ja ein wenig gelogen. Stell Dir vor, eine virtuelle Funkltion braucht ein korrekt initialisiertes Member. Dann darf die erst aufgerufen werden, wenn der Konstruktor durch ist.
-
Hmm ha I see, I see.
Gibt es vielleicht einen Workaround um dasselbe zu erreichen? Ich benötige dies fürs Exception Handling und finde es ein wenig doof, in jeder Exception noch einen String mit dem Namen der Exception mitgeben zu müssen
-
Ishildur schrieb:
Hmm ha I see, I see.
Gibt es vielleicht einen Workaround um dasselbe zu erreichen? Ich benötige dies fürs Exception Handling und finde es ein wenig doof, in jeder Exception noch einen String mit dem Namen der Exception mitgeben zu müssen
Aber das Exception-Objekt ist doch vollständig Konstruiert, wenn Du die what() aufrufst. Null Problemo.
-
Hmm das funktioniert leider auch nicht, IMHO aus demselben Grund. B ist doch bei dieser Variante immer noch nicht konstruiert, wenn ich typeid(*this) aufrufe?
class A:std::exception{ public: A(void){ std::cout << typeid(*this).name() << std::endl; std::cout << this->what() << std::endl;} virtual ~A(void){} }; class B:A{ }; void main(){ B b; system("PAUSE"); }Output:
class A
UnknownException
-
Ach, ich dachte, Du fängst die in der main() und gibst dort what() aus.
-
Ishildur schrieb:
class A:std::exception { public: A(void){ std::cout << typeid(*this).name() << std::endl; std::cout << this->what() << std::endl; } virtual ~A(void){} };Die Regel ist ganz einfach: Wenn Du im Konstruktor1 oder Destruktor2 eine virtuelle Funktion des Objektes aufrufst, dann wird das nie eine Funktion einer abgeleiteten Klasse sein, weil der "abgeleitete Teil" entwender noch nicht1 oder nicht mehr2 verfügbar ist. Das schließt auch die dynamische Typinformation ein.
-
@Sebastian Pizer
Ja das habe ich inzwischen schon verstanden
Meine Frage ist nun ob es für dieses Problem einen bekannten Workaround gibt?
-
Ishildur schrieb:
Meine Frage ist nun ob es für dieses Problem einen bekannten Workaround gibt?
typeid nicht im Konstruktor aufrufen?
Für dieses spezielle Problem könntest du vielleicht
__FUNCTION__benutzen, was manche Compiler zur Verfügung stellen:class A: public std::exception { public: A(const char* id) { std::cout << id << std::endl; } virtual ~A() throw() {} }; class B: public A { public: B() : A(__FUNCTION__) { } }; int main() { B b; }Wenn dein Compiler/Preprocessor
__FUNCTION__kennt, macht der Code das, was du willst. Ist aber nicht hübsch, oder besonders portabel.Und noch ein paar Standard-Belehrungen:
void main()ist falsch -int main()ist richtigvoidin den leeren Klammern einer Funktionsdeklaration ohne Parameter ist in C++ unnötig. Ein C-Relikt.throw()hinter dem Destruktor einerstd::exception-Ableitung ist ratsam, dann klappts auch mit allen Compilern
- Du willst in diesem Fallpublic-Vererbung (ist-ein), nichtprivate(hat-ein)
-
Ishildur schrieb:
Hmm das funktioniert leider auch nicht, IMHO aus demselben Grund. B ist doch bei dieser Variante immer noch nicht konstruiert, wenn ich typeid(*this) aufrufe?
Es ist vollkommen sinnfrei in C++ im Konstruktor typeid aufzurufen, da der Typ der Klasse im Kontruktor ohnehin bekannt ist. Es gibt keine "virtuellen" Konstruktoren in C++.
Also, formulieren Deine Klasse um.