dynamic_cast-Problem



  • Ich habe hier einen kleinen Code mit drei Klassen und verwende dynamic_cast um den Typen zu ändern:

    #include <windows.h>
    
    #define DEBUG
    
    class Mammal {
    	public:
    		virtual void speak() const { cout<<"mammal is speaking!\n"; }
    };
    
    class Cat : public Mammal {
    	public:
    		Cat() {++number;}
    		virtual void speak() const { cout<<"cat is speaking!\n"; }
    		void sleep() const { cout<<"cat is sleeping\n"; }
    		static int howmany() { return number; }
    	private:
    		static int number;
    };
    
    int Cat::number=0;
    
    class Dog : public Mammal {
    	public:
    		virtual void speak() const { cout<<"wuff\n"; }
    };
    
    int main(void)
    {
    	Mammal* ptr=new Cat;
    	Cat* c=dynamic_cast<Cat*>(ptr);
    
    	return 0;
    }
    

    Der Compilerfehler:

    warning C4541: 'dynamic_cast' fuer polymorphen Typ 'class Mammal' mit /GR- verwendet; unvorhersehbares Verhalten moeglich

    Ich hab schon in der MSDN nachgelesen, aber keines der dort fuer den Fehler erklaerten Gruende trifft hier zu; die Klassen sind weder private abgeleitet noch existiert da irgendwo eine Mehrfachvererbung. Und was bedeutet "mit /GR-verwendet"? Kann mir jemand helfen?

    Danke.



  • Du musst in den Projekteinstellungen angeben, dass der Compiler RTTI verwenden soll.
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/_core_.2f.GR_option.asp



  • Oh danke!



  • Weiss nicht was du hiermit bezwecken willst

    Mammal* ptr=new Cat;
        Cat* c=dynamic_cast<Cat*>(ptr);
    

    aber würde folgendes nicht auch reichen

    Cat* c = new Cat;
        Mammal* ptr = c;
    

    new gibt einen Zeiger auf das erstellte Objekt zurück, also sollte man es auch so handhaben. Und dynamic_cast sollte man wirklich nur in Extremsituationen verwenden, denn im Gegensatz zu den anderen Casts wird dieser zur Laufzeit ausgewertet und frisst nur unnötig Performance.



  • Hi groovemaster2002,

    das was du machst und das was er tut sind doch zwei völlig verschiedene Sachen.
    Du erzeugst ein Objekt der abgeleitetet Klasse und weist diesem einen Zeiger auf die Basisklasse zu. Das funktioniert auch ohne explziten Cast.
    Er jedoch erzeugt ein Object der abgeleitetet Klasse und weist diesem einen Zeiger auf die Basisklasse zu UND weist dieses anscliessend einem Zeigt auf die abgeleitete Klasse zu. Um dieses Casting sicher zu machen verwendet man üblicherweise dynamic_cast.
    Ich hoffe das im Programm dann aber auch das Ergbnis des dynamic_cast gegen 0 geprüft wird wie sich das gehört 😋



  • Helper schrieb:

    Er jedoch erzeugt ein Object der abgeleitetet Klasse und weist diesem einen Zeiger auf die Basisklasse zu UND weist dieses anscliessend einem Zeigt auf die abgeleitete Klasse zu.

    Yep, genau das macht er und für mich hört sich das ziemlich unsinnig an. Sicher ist sein Code und meiner nicht dasselbe, aber das Ergebnis schon:
    - Instanz der abgeleiteten Klasse erzeugen
    - c ist Zeiger auf Objekt der abgeleiteten Klasse
    - ptr ist Zeiger auf Objekt der Basisklasse



  • Ja, dass mache ich, um an die Funktionen
    void sleep() const { cout<<"cat is sleeping\n"; }
    und
    static int howmany() { return number; }
    ranzukommen, was ich mit

    Cat* c = new Cat;
    Mammal* ptr = c;
    

    aber nicht kann.



  • Wieso nicht?
    Schon mal mit

    c->sleep()
    

    probiert?
    Ausserdem sind für howmany() die instanzierten Objekte eh egal, da du das ja so aufrufst:

    Cat::howmany()
    


  • http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/_core_.2f.gr_option.asp
    außerdem fehlt deiner klasse ein virtueller destruktor (damit delete richtig funktioniert)- ist aber wahrscheinlich nur ein minimalbeispiel und daher egal.



  • groovemaster2002 schrieb:

    Wieso nicht?
    Schon mal mit

    c->sleep()
    

    probiert?

    Nein, aber das weiß man doch?!

    Wie soll den aufgelößt werden, wenn Mammal sleep() nicht einmal unterstützt?



  • zuvieleVerwendeteNamen schrieb:

    Nein, aber das weiß man doch?!

    Sry, ich wusste es jedenfalls nicht. 😉

    zuvieleVerwendeteNamen schrieb:

    Wie soll den aufgelößt werden, wenn Mammal sleep() nicht einmal unterstützt?

    Was willst du denn hier auflösen und wieso mit Mammal? c ist vom Typ Cat und damit weiss der Compiler wo er sleep() hernehmen soll.
    Also entweder haben wir ein Verständigungsproblem (weil ich vielleicht deinen ganzen Code nicht kenne) oder du hast ein Verständnisproblem. Schau dir deinen und meinen Code noch mal genau an, und lass ihn dir gründlich durch den Kopf gehen.
    Imo liegt dein Problem darin, dass du folgendes machst:

    A* p = new B;
    

    Was eigentlich unüblich ist und ich das bisher auch noch nie gesehen hab. Was aber nicht's heissen muss. 🙂
    Normalerweise macht man es so:

    B* p = new B;
    

    Und wenn du dann einen Zeiger auf die Basisklasse brauchst, reicht ein impliziter Cast.


Anmelden zum Antworten