Anzeige:
Ergebnis 1 bis 9 von 9

Thema: Ärger mit Mehrfachvererbung in C++

  1. #1
    Registrierter Benutzer
    Registriert seit
    08.07.2002
    Beiträge
    719

    Ärger mit Mehrfachvererbung in C++

    Ich hab heute ein bißchen Ärger mit Mehrfachvererbung gehabt: Meiner Meinung nach sollte folgendes Programm "Item::start" ausgeben, es gibt aber "Item::draw" aus:
    Code:
    #include <iostream>
    
    using namespace std;
    
    class Item {
    	public:
    		virtual void start() { cerr << "Start" << endl; }
    };
    
    class Sprite {
    	public:
    		virtual void draw() { cerr << "Draw" << endl; }
    };
    
    class Object : public Sprite, public Item {
    	public:
    		void start() { cerr << "Item::start" << endl; }
    		void draw() { cerr << "Item::draw" << endl; }
    };
    
    int main(int argc, char** argv) {
    	Object* obj = new Object();
    	Sprite* spr = (Sprite*)obj;
    	Item* itm = (Item*)spr;
    	itm->start();
    }
    Ich nehme mal an, dass das nicht vorgesehen ist und mir das Programm eigentlich mit einem Segfault abschmieren. In Java darf man meiner Meinung nach sowas machen und in C++ sollte es auch gehen, da ja die Adresse des Pointers die gleiche bleibt. Wenn man von obj direkt auf itm castet, geht es auch.

  2. #2
    Registrierter Benutzer
    Registriert seit
    24.06.2003
    Beiträge
    486

    Re: Ärger mit Mehrfachvererbung in C++

    Original geschrieben von axeljaeger
    und in C++ sollte es auch gehen, da ja die Adresse des Pointers die gleiche bleibt.
    Der richtige Cast in diesem Fall ist dynamic_cast (zur Laufzeit), während der C-Style Cast in diesem Fall einem static_cast (zur Compilezeit) entspricht.

    Code:
    Object* obj = new Object();
    Sprite* spr = obj;
    if(Item* itm = dynamic_cast<Item*>(spr))
    {
    	cout << static_cast<void*>(itm) << endl;
    	itm->start();
    }
    Item* itm = (Item*)spr;
    cout << static_cast<void*>(itm) << endl;
    itm->start();

  3. #3
    Registrierter Benutzer
    Registriert seit
    08.07.2002
    Beiträge
    719
    ich muss also dynamic_cast verwenden, aber woher weis man das und was genau läuft da schief?

  4. #4
    Registrierter Benutzer
    Registriert seit
    24.06.2003
    Beiträge
    486
    Original geschrieben von axeljaeger
    ich muss also dynamic_cast verwenden, aber woher weis man das
    Der 'Trick' ist nie C Casts in C++ zuwenden (siehe dazu Rest des Textes).
    Wenn man sich daran hält bekommt man vom Compiler schon die entsprechende Fehlermeldung vorgesetzt.

    und was genau läuft da schief?
    Das hängt damit zusammen,wie virtuelle Funktionsaufrufe in C++ implementiert sind.
    Eine Klasse,die direkt von zwei Klassen mit vtable ableitet, hat nicht nur eine vtable, sondern zwei (entsprechend für n verschiedene direkte Oberklassen).
    Das Speicherlayout in diesem Bsp wäre etwa
    Code:
    ------------
    |  Sprite  |
    |            ---> Zeiger auf vtable von Sprite
    ------------
    |  Item    |
    |            ---> Zeiger auf vtable von Item
    ------------
    |  Object  |
    |              
    ------------
    Code:
    Object* obj = new Object();
    Sprite* spr = obj;
    Item* item = obj;//<-- neu hinzugefügt
    Bei der Zuweisung obj an spr muß der this-Pointer angepasst werden, damit er auf das Sprite Subobjekt zeigt (glücklicherweise ist in diesem Fall für den Compiler nichts zu tun, Sprite ist 1.Oberklasse von Objekt und damit sind die Adressen bereits korrekt).
    Nächster Fall, obj an item, jetzt muß zur Compilezeit Code erzeugt werden, der den this-Pointer anpasst, damit er auf das Item Subobjekt zeigt.
    Der Code vom Compiler könnte etwa so aussehen:
    Item* item = obj + sizeof(Sprite);
    (lass' dir die Adressen von obj,spr und item einmal ausgeben)
    Wichtig ist diese Verschiebung für den Zugriff auf nicht virtuelle Funktionen/oder Member von item.
    Nun zu
    Code:
    Item* itm = (Item*)spr;
    Was haben Item und Sprite gemeinsam?Im Grunde doch nichts, es sind zwei völlig unabhängige Klassen, das sie beide Oberklasse von Objekt sind spielt hier jetzt keine Rolle.Der Compiler sieht nur einen Sprite Pointer (rechts) und einen Item Pointer (links).
    [das bringt mich auch jetzt gerade dazu, daß der C Cast in diesem Fall kein static_cast ist (weil Cast zwischen zwei völlig verschiedenen Pointer), sondern ein reinterpret_cast,was gleich wieder ein gutes Argument gegen C Casts in C++ ist ,mit static_cast wäre das nicht passiert (es hätte sich nicht kompilieren lassen)].
    Er kann zur Compilezeit den this Zeiger nicht anpassen, erst zur Laufzeit weiß er, daß spr in Wirklichkeit auf ein Objekt zeigt.

  5. #5
    Registrierter Benutzer
    Registriert seit
    08.07.2002
    Beiträge
    719
    Ich hatte BISHER immer den C-Style-cast verwendet, aber hauptsächlich, weil ich keine befriedigende Erklärung über die C++-Castingoperatoren gesehen hab. Vielleicht sollte ich jetzt damit aufräumen. Hat jmd. einen guten Link zu einer kurzen Erklärung über das casting? Meine C++-Bücher schweigen sich da aus.

  6. #6
    Registrierter Benutzer
    Registriert seit
    24.06.2003
    Beiträge
    486
    Original geschrieben von axeljaeger
    IHat jmd. einen guten Link zu einer kurzen Erklärung über das casting? Meine C++-Bücher schweigen sich da aus.
    Du brauchst bessere Bücher .
    Na hier eine kurze Erläuterung von Dietmar Kuehl
    Klick
    Gibt sicherlich noch ausführliche Erklärungen.

  7. #7
    Registrierter Benutzer Avatar von panzi
    Registriert seit
    04.05.2001
    Ort
    Kottingbrunn
    Beiträge
    609
    Original geschrieben von wraith
    Du brauchst bessere Bücher .
    Na hier eine kurze Erläuterung von Dietmar Kuehl
    Klick
    Gibt sicherlich noch ausführliche Erklärungen.
    Oder in "C++ in a Nutshell" wird fast alles zu C++ (und auch C!) erklärt. (Nur die Beschreibung zu throw() hinter Funktionsdeklaratioenen hab ich dort nicht gfunden, wie ich in einen anderen Thread erwähnt hab.)
    Jedenfalls die C++ casts werden dort auch recht gut erklärt.
    Intel Core 2 Duo CPU 2.66GHz; Nvidia GeForce 8 8800 GTS; 4GB RAM; Fedora 12; KDE-testing

  8. #8
    Registrierter Benutzer
    Registriert seit
    08.07.2002
    Beiträge
    719
    Zu den Büchern: Ich habe hier "C++ echt einfach", das finde ich für seine 300 Seiten richtig gut und "C++ Grundlagen" von Data Becker. Das finde ich für seine 1000 Seiten ziemlich schlecht, von STL wird da nichts erwähnt und diese cast-operatoren fehlen auch. Ich kann also vom Kauf dieses Buches nur abraten.

  9. #9
    Registrierter Benutzer Avatar von peschmae
    Registriert seit
    14.03.2002
    Ort
    Schweizland
    Beiträge
    4.549
    Ich hab den Stroustroup - The C++ Programming Language. Recht nett aber ein Brocken der nicht leicht zu verdauen ist
    Aber so ist C++ wohl halt. Die C++-Cast Dinger sind dort auf jeden Fall auch drin und erläutert

    MfG Peschmä
    The greatest trick the Devil ever pulled was convincing the world he didn't exist. -- The Usual Suspects (1995)
    Hey, I feel their pain. It's irritating as hell when people act like they have rights. The great old one (2006)

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •