Frage zu dynamic_cast
-
Hi
class A { public: A () {cerr << " Ich bin ein A!" << endl;} void Call() {cerr << " Ich bin ein A-Call!" << endl;} }; class B: public A { public: B () {cerr << " Ich bin ein B!" << endl;} void Call() {cerr << " Ich bin ein B-Call!" << endl;} }; class C: public B { public: C () {cerr << " Ich bin ein C!" << endl;} void Call() {cerr << " Ich bin ein C-Call!" << endl;} }; void Test1() { cerr << "test1!" << endl; cerr << "A!" << endl; A my_a; cerr << endl; cerr << "B!" << endl; B my_b; cerr << endl; cerr << "C!" << endl; C my_c; cerr << endl; A* my_a_ptr = 0; B* my_b_ptr = 0; C* my_c_ptr = 0; my_a_ptr = &my_a; cerr << "my_a_ptr" << endl; my_a_ptr->Call(); my_c_ptr = &my_c; cerr << "my_c_ptr" << endl; my_c_ptr->Call(); my_b_ptr = &my_b; cerr << "my_b_ptr" << endl; my_b_ptr->Call(); my_a_ptr = new B(); cerr << "my_a_ptr = new B()" << endl; my_a_ptr->Call(); my_b_ptr = dynamic_cast<B*> (my_a_ptr); my_b_ptr->Call(); }
fuehrt zu
test1.cpp:xx: error: cannot dynamic_cast ‘my_a_ptr’ (of type ‘class A*’) to type ‘class B*’ (source type is not polymorphic)
ersetzt man das ganze durch einen static_cast klappt alles wie gewuenscht ...
wieso ist das so?Gruesse
-
Gleich noch eine hinterher
cerr << "my_a_ptr = new B()" << endl; my_a_ptr = new B(); my_a_ptr->Call(); cerr << endl; cerr << "my_b_ptr = static_cast<B*> (my_a_ptr)" << endl; my_b_ptr = static_cast<B*> (my_a_ptr); my_b_ptr->Call(); cerr << endl; cerr << "my_c_ptr = static_cast<C*> (my_a_ptr)" << endl; my_c_ptr = static_cast<C*> (my_a_ptr); my_c_ptr->Call(); cerr << endl;
fuehrt zu:
my_a_ptr = new B()
Ich bin ein A!
Ich bin ein B!
Ich bin ein A-Call!my_b_ptr = static_cast<B*> (my_a_ptr)
Ich bin ein B-Call!my_c_ptr = static_cast<C*> (my_a_ptr)
Ich bin ein C-Call!Warum kann ich my_a_ptr in einen C* casten (nur statisch natuerlich) obwohl es nur die Information eines B* enthaelt? Wird im Zweifelsfall dann nicht information hinzugedichtet?
Gruesse
-
Frager schrieb:
...
class A { public: A () {cerr << " Ich bin ein A!" << endl;} void Call() {cerr << " Ich bin ein A-Call!" << endl;}
...
Hi,
schreib da mal "virtual" vor:
virtual void Call() { ...
(kannst Du bei den "Kindern" uch machen, ist da dann aber egal).
Du brauchst da gar keinen cast ....Und die ganze "Pointerei" ist auch ziemlich überflüssig:
void Test2(A* a) { a->Call(); } void Test1() { A my_a; B my_b; C my_c; my_a.Call(); my_b.Call(); my_c.Call(); Test2(&my_a); Test2(&my_b); Test2(&my_c);
Allerdings scheint nicht ganz klar zu sein, was Du willst: Soll Dein Objekt eine (je nach Klasse speziell zugeschnittene) Funktion haben, dann nimm virtual .... wenn nicht, dann sollten sie auch nicht denselben Namen haben.
Gruß,
Simon2.
-
ok,
dann funktioniert dynamic_cast bei A* -> B* und bei A* -> C* gibt es eine segmention fault.
Static_cast laeuft wie gehabt ...
Erklaerungen?
-
Frager schrieb:
ok,
dann funktioniert dynamic_cast bei A* -> B* und bei A* -> C* gibt es eine segmention fault.
Static_cast laeuft wie gehabt ...
Erklaerungen?
Ich glaube, Du bekommst da was "kerndurcheinander":
Wenn eine Klasse B von A erbt, dann will man damit üblicherweise ausdrücken, dass jedes B ein A ist. D.h. Du kannst alles, was Du mit einem A machen kannst, auch mit einem B machen (hier z.B. Call() aufrufen).
Das weiß der Compiler auch und Du brauchst es ihm nicht mehr über einen (dynamic-)cast mitzuteilen.Mit einem "cast" sagst Du dem Compiler "Ich weiß es besser als Du" .... aber das sollte natürlich auch stimmen.
In Deinem Fall (gibt es wirklich einen "segmentation fault" ? Oder nicht doch eher eine unhandled exception ?) hast Du ihm bestimmt ein X für ein U vorgemacht .. so in der Art:A* a = new B(); // das Objekt, auf das a zeigt, ist ein B C* c = dynamic_cast<C*>(a); // FEHLER !! Das Objekt ist und bleibt ein B // und egal, was Du davorschreibst: Es wird kein C daraus ! // Da Du aber dem Compier gesagt hast, dass Du es besser weißt, kann er // nichts dagegen machen.
Vergleich das mit sprechenderen Klassennamen:
class Lebewesen {} class Tier : public Lebewesen { virtual void fressen();} class Elefant : public Tier { void ruesselBlasen();} Lebewesen* tier = new Tier(); Elefant* e = dynamic_cast<Elefant*>(tier); e->ruesselBlasen(); // Autsch ! Ein Elefant ist zwar ein Tier, aber nicht jedes Tier ist ein Elefant
Gruß,
Simon2.
-
Hallo Frager
Mit static_cast zwingst Du den Compiler die Umwandlung vorzunehmen. Der Compiler kann im allgemeinen nicht wissen, ob hinter dem Zeiger auf A ein Objekt vom Typ A,B oder C liegt. Du sagst, Du weißt es und der Compiler vertraut Dir. Das Du danach mit dem falsch gecasteten Zeiger noch weiterarbeiten kannst, ist purer Zufall. (Auch undefiniertes Verhalten gennant). Du könntest genauso einen Seg_Fault bekommen, oder es passieren noch schlimmere Dinge.
Beim Dynamic_cast wird erst zur Laufzeit festgestellt, ob die dynamische Umwandung
möglich ist. (Dazu brauchst Du mindesten eine virtuelle Methode).
Wenn die Umwandlung nicht möglich ist bekommst Du einen NULL-Pointer zurück. Und den darfst Du natürlich nicht dereferenzieren. --> SegFault.DJohn