Conversion von Dateitypen



  • Nach dem Durchlesen der FAQ-Beiträge seh ich bis jetzt keinen Sinn in der Verwendung dieses neumodischen static/dynamic_cast Schnickschnacks :
    dynamic_cast bei Klassen wird doch wohl in den meißsten Fällen durch richtiges Verwenden von virtuellen Funktionen überflüssig und static_cast ist ja anscheinend das Gleiche wie der gute alte cast, nur unübersichtlicher und länger zu schreiben.

    Dann lies noch mal richtig. Weder ist der static_cast das gleiche wie der C-Cast noch ist der dynamic_cast Schnickschnack. So lassen sich z.B. einige casts ausschließlich mit dem dynamic_cast realisieren.

    Wie funktioniert dieser dynamic_cast eigentlich?

    Das ist sein Geheimnis. Das entscheidene ist aber, dass der dynamic_cast ein *Laufzeit*-Cast ist. Er verwendet zur Laufzeit RTTI-Informationen (ähnlich wie der Exception-Mechanismus) und kann anhand dieser Informationen entscheiden ob ein Cast möglich ist oder nicht. Ist er möglich, wir der Cast durchgeführt. Ist er nicht möglich, liefert er entweder einen Nullzeiger (falls ein Zeiger gecastest wurde) oder wirft eine bad_cast-Exception (falls eine Referenz gecastet wurde).



  • Jetzt bin ich aber verwirrt.

    Original erstellt von HumeSikkins:
    ... Demzufolge ist: return unsigned(Wert); von der Bedeutung her äquivalent zu:
    return static_cast<unsigned>(Wert);

    Wo liegt denn nun dann der Unterschied zwischen static_cast und c-cast?
    Aus den 2 FAQ-Beiträgen werd' ich nicht schlauer.

    PS: Und nen Beispiel für den sinnvollen Einsatz von dymanic_cast wär noch nett.

    [ Dieser Beitrag wurde am 28.06.2003 um 18:28 Uhr von C14 editiert. ]



  • Wo liegt denn nun dann der Unterschied zwischen static_cast und c-cast?

    In der Mächtigkeit. Der C-Cast beherrscht die Vereinigung der Möglichkeiten des static_cast, reinterpret_cast und des const_cast.

    Mit dem static_cast kann man generell genau dann einen Typ s in einen Typ t konvertieren, wenn es eine *implizite* Konvertierung von t nach s gibt.
    Man kann damit also z.B. ein int in eine enum casten, arithmetische Konvertierungen durchführen oder in einfachen Hierarchien einen downcast von Base* (bzw. Base&) nach Derived* (bzw. Derived&) durchführen.

    Und nen Beispiel für den sinnvollen Einsatz von dymanic_cast wär noch nett.

    Da gibt es unzählige. Z.B. immer wenn du einen Pointer Base in einen Pointer Derived casten willst, du aber nicht sicher bist, ob der dynamische Typ tatsächlich zu Derived-kompatibel ist, kommst du um einen dynamic_cast nicht rum.

    Sobald du außerdem mit mehrdeutigen Vererbungs-Hierarchien arbeitest (mehrfache/wiederholte bzw. virtuelle Vererbung), kannst du nur noch den dynamic_cast zum downcasten benutzen.

    Alles in Allem verhält sich der alte C-Cast zu den neuen C++-Casts so wie Vorschlaghammer zu Feinwerkzeug.



  • Verstehe, die neuen casts sind also differenzierter.

    Wahrscheinlich liegt das Benutzen von dymanic_cast aber auch häufig an nem falschen design.
    Wann macht es Sinn einen Base-Pointer in einen Derived umzuwandeln? (das meinte ich mit Beispiel, sorry)
    Nachher kommt noch sowas dabei heraus:

    if (d1=dynamic_cast<Derived1*>(pBase)) d1->f_von_d1();
    if (d2=dynamic_cast<Derived2*>(pBase)) d2->f_von_d2();
    ...
    

    @volkard:
    diese geheimen Felder in der vtbl machen mir etwas Angst, vor allem seitdem ich typeid(...).name() gesehen hab: Heißt das etwa, dass ich in meiner fertig-gebackenen exe bald die Klassennamen samt Abstammung wiederfinden kann?



  • Original erstellt von C14:
    @volkard:
    diese geheimen Felder in der vtbl machen mir etwas Angst, vor allem seitdem ich typeid(...).name() gesehen hab: Heißt das etwa, dass ich in meiner fertig-gebackenen exe bald die Klassennamen samt Abstammung wiederfinden kann?

    wenn du typeid und dynamic_cast verwendest, kann das schon mal sein.



  • @Hume:
    IMHO ist das großer schwachsinn... (oder kannst du mir erklären warum das gut so ist -> das wäre natürlich ideal)

    meine Container halten sich da nicht daran -> also verwende ich weiterhin container::size_type wenn ich eine größenangebe brauche...

    [edit]zweite seite übersehen, ich beziehe mich darauf dass size_type == size_t sein muss[/edit]

    [ Dieser Beitrag wurde am 28.06.2003 um 20:09 Uhr von Shade Of Mine editiert. ]



  • @Shade
    Ich sehe gerade, dass Container::size_type nicht von Allocator::size_type abhängen muss (nur für std::string müssen die beiden gleich sein). Damit gilt für Container::size_type nur, dass es sich hier um einen "unsigned integral type" handeln muss.

    @C14
    Such einfach mal ein bischen im Forum.
    Ich habe hier z.B. schon mal was über Contract Programming geschrieben.
    dynamisches casten böse?

    Da macht ein dynamic_cast durchaus mal sinn, ohne das es sich gleich um ein Design-Fehler handelt. Ich könnte jetzt auch mit dem azyklischen Visitor-Pattern kommen, aber das ist wohl etwas zu weit her geholt 🙂



  • Original erstellt von HumeSikkins:
    **Ich habe hier z.B. schon mal was über Contract Programming geschrieben.
    dynamisches casten böse?
    **

    Ich quote mal aus dem alten Thread, weil ich den nicht wieder vorholen will:

    Nimm zum Beispiel einfach mal die Fähigkeit serialisierbar zu sein. Du könntest also ein Interface Serializable haben und eine Millionen Typen können dieses Interface implementieren (statt diese Fähigkeit einfach in eine gemeinsame Basisklasse zu stopfen, was auf die Dauer zu fetten Interfaces führt)

    Dann fragst du irgendwo:

    if ((Serializable* p = dynamic_cast<Serializable*>(Bla)) 
       p->Save();
    

    Das versteh ich nicht. Wenn 'Bla' jetzt keine Basisklasse 'Serializable' hat, dann funktioniert dieser Cast doch garnicht?



  • @volkard:
    Die entsprechenden Felder werden also nur angelegt, wenn sie auch benötigt werden? Aber weiß das der Compiler immer?
    Wie sieht's z.B. mit ner DLL aus, die mit ner factory-Funktion ne abgeleitete Klasse exportiert. Funktioniert dann typeid(...).name() mit dieser Klasse im Hauptprogramm?

    @Dr. Green:
    Bla ist Zeiger auf Basisklasse, Serializable ist davon abgeleitet.
    Jetzt soll mit dem cast geschaut werden, ob bla auch vom Typ Serializable ist und falls ja gespeichert werden.
    Die Verwendung war mir auch neu... dachte dynamic_cast springt nur an, wenn es sich tatsächlich um nen Serializable-Object handelt, aber anscheinend gehts auch bei von Ser. abgeleiteten Klassen.

    [ Dieser Beitrag wurde am 29.06.2003 um 10:31 Uhr von C14 editiert. ]



  • Original erstellt von HumeSikkins:
    Damit gilt für Container::size_type nur, dass es sich hier um einen "unsigned integral type" handeln muss.

    Das klingt gut - also ist mein size_type doch nicht sinnlos 🙂



  • Original erstellt von Shade Of Mine:
    Das klingt gut - also ist mein size_type doch nicht sinnlos 🙂

    Seh ich anders, oder zeig mir mal eine Implementierung bei der Container::size_type != size_t ist.



  • Original erstellt von Lars:
    Seh ich anders, oder zeig mir mal eine Implementierung bei der Container::size_type != size_t ist.

    zB meine container (da hab ich manchmal unsigned __int64 als size datentyp (bzw. unsigned long long).
    tatsache ist, dass es nicht nur container in der stdlib gibt, und die anderen (sofern sie interface kompatible sind) sollten man doch auch benutzen koennen - schliesslich ist das der sinn von containern, oder?

    nur sag mir, wo liegt der nachteil bei meiner methode?



  • Original erstellt von Shade Of Mine:
    nur sag mir, wo liegt der nachteil bei meiner methode?

    Mehr Schreibarbeit, schlechtere Lesbarkeit.



  • Original erstellt von Lars:
    Mehr Schreibarbeit, schlechtere Lesbarkeit.

    schreibarbeit?
    ein typedef - auch du meine guete, das zaehlt nicht als mehr schreibarbeit!
    schlechtere lesbarkeit?

    size_type size() const;
    versus
    size_t size() const;

    was kannst du schlechter lesen?
    ich kann beides ohne probleme auf den ersten blick erkennen.

    nur das size_type nicht verraet was fuer typen ich intern verwende, mit size_t habe ich mich festgelegt und darf nicht auf unsigned long long umsteigen wenn ich es brauche, bei mir muss ich nur ein typedef aendern.

    und wenn du sowieso size_type anbietest, als typedef auf size_t, dann sind die beiden varianten sowieso aequivalent (solange der intern verwendete container als size_type size_t hat, wenn nicht dann ist meine variante besser :p)



  • Original erstellt von C14:
    **@Dr. Green:
    Bla ist Zeiger auf Basisklasse, Serializable ist davon abgeleitet.
    Jetzt soll mit dem cast geschaut werden, ob bla auch vom Typ Serializable ist und falls ja gespeichert werden.
    **

    hm.. Aber dann muss ja letztendlich doch jedes speicherbare Objekt von Serializable abgeleitetet sein. 😕



  • Glaust du wirklich das dein Container unsigned __int64 (-1) aufnehmen kann 😮 Ich bezweifele das doch sehr.

    [ Dieser Beitrag wurde am 30.06.2003 um 14:43 Uhr von Lars editiert. ]



  • Original erstellt von Lars:
    Glaust du wirklich das dein Container unsigned __int64 (-1) aufnehmen kann 😮 Ich bezweifele das doch sehr.

    wie kommst du auf -1 ??



  • Original erstellt von Shade Of Mine:
    wie kommst du auf -1 ??

    representiert den gröstmöglichen Wert.



  • Original erstellt von Lars:
    representiert den gröstmöglichen Wert.

    und? ich sehe immer noch kein problem darin, dass mein container mehr als 4 milliarden eintraege haben kann.

    schliesslich muss man auch an die zukunft denken und man muss nicht zwangslaeufig alles im RAM halten - man kann ja auf die festplatte auslagern.

    aber size_type muss ja nicht __int64 sein, es kann ja auch char sein - wenn ein container nicht viele elemente beinhalten kann (zB weil es nur eine lookup table darstellen).

    sag mir einfach nur mal einen nachteil von meiner methode!

    ein typedef mehr schreibarbeit zaehlt nicht!
    und ob da jetzt size_t oder size_type steht, ist von der lesbarkeit gleich.



  • Original erstellt von Shade Of Mine:
    **ein typedef mehr schreibarbeit zaehlt nicht!
    **

    Doch natürlich. Besonders das Nachschauen, worum es sich denn überhaupt handelt (weil man früher oder später doch casten muss) empfinde ich als Ärgernis.

    Das sind die Punkte wo C++ keinen Spaß mehr macht, weil man ständig andere Datentypen hat, obwohl sich hinter den verschiedenen Bezeichnern ohnehin dasselbe verbirgt.


Anmelden zum Antworten