static_cast<> für upcast?
-
Hallo
angenommen, ich habe eine basisklasse "base" und eine abgeleitete klasse
"derived", sowie eine weitere klasse, die per MI als basis für "derived" dient.class base { }; class stuff // stellvertreter für etwas anderes { }; class derived : public base, public stuff { };und angenommen, ich habe ein objekt, was zu 100% ein "derived" ist,
sowie ein "base" pointer darauf:derived d; base *b = &d;darf ich dann davon ausgehen, dass ein "static_cast<derived *>" ein gültigen
zeiger zurückliefert?derived *pd = static_cast<derived *>(b); assert(&d == pd);könnte die mehrfachvererbung wegen this-verschiebung problematisch werden?
ich möchte nur auf jeden fall dynamic_cast vermeiden.
geht das?MfG cast-spaß
-
mist, ich meinte downcast -.-
-
Das ist ein Downcast..
Und warum willst du dynamic_cast nicht verwenden? Der ist ja genau für das da und mit dem kannst du auch prüfen, ob die Konvertierung geklappt hat.
Im übrigen solltest du vlt. nochmal darüber nachdenken, ob der Downcast überhaupt nötig ist..
-
drakon schrieb:
Und warum willst du dynamic_cast nicht verwenden? Der ist ja genau für das da und mit dem kannst du auch prüfen, ob die Konvertierung geklappt hat.
Ohne RTTI ist kein dynamic_cast möglich, da muss man sicher sein, dass es geht und einen static_cast machen.
-
Superlexx schrieb:
drakon schrieb:
Und warum willst du dynamic_cast nicht verwenden? Der ist ja genau für das da und mit dem kannst du auch prüfen, ob die Konvertierung geklappt hat.
Ohne RTTI ist kein dynamic_cast möglich, da muss man sicher sein, dass es geht und einen static_cast machen.
Was willst du mir damit sagen?
RTTI ist involviert man darf es benutzen und muss es nicht selbst von Hand nachbauen..
-
cast-spaß schrieb:
und angenommen, ich habe ein objekt, was zu 100% ein "derived" ist, sowie ein "base" pointer darauf:
[...]
darf ich dann davon ausgehen, dass ein "static_cast<derived *>" ein gültigen
zeiger zurückliefert?Ja.
cast-spaß schrieb:
könnte die mehrfachvererbung wegen this-verschiebung problematisch werden?
Nein,
static_castsorgt in diesem Fall für einen korrekten Downcast. Allerdings nur, solangebasekeine virtuelle Basisklasse vonderivedist. Und du musst dir wirklich sicher sein, ansonsten hast du undefiniertes Verhalten.Wenn du Sicherheit im Debug-Modus und Effizienz im Release-Modus erreichen möchtest, kannst du dir einmal
boost::polymorphic_downcastanschauen.
-
Nexus schrieb:
cast-spaß schrieb:
könnte die mehrfachvererbung wegen this-verschiebung problematisch werden?
Nein,
static_castsorgt in diesem Fall für einen korrekten Downcast. Allerdings nur, solangebasekeine virtuelle Basisklasse vonderivedist. Und du musst dir wirklich sicher sein, ansonsten hast du undefiniertes Verhalten.jo, ich bin mir sicher. mehr als 100% geht doch nicht?

allerdings ist,
baseeine virtuelle basisklasse von `derived[/b].wenn ein statischer upcast möglich ist, warum dann nicht auch ein statischer
downcast?
boost verwendet intern auch nur einen [c]static_cast` .
-
cast-spaß schrieb:
allerdings ist,
baseeine virtuelle basisklasse von [c]derived[/b]. wenn ein statischer upcast möglich ist, warum dann nicht auch ein statischer downcast?Weil die Lage des virtuellen Basisklassensubobjektes relativ zu davon abgeleiteten Subobjekten vom Typ des vollständigen Objektes abhängt. Im Falle eines Basisklassenpointers ist der vollständige Typ aber werder bekannt, noch kann er im Falle nichtpolymorpher Klassen ermittelt werden, und es gibt keine Möglichkeit, dies dem Castoperator mitzuteilen.
Eine implizite Konvertierung eines Zeigers auf ein Objekt einer abgeleiteten Klasse in einen Zeiger auf das virtuelle Basisklassensubobjekt ist deshalb möglich, weil hierfür zusätzliche Informationen im Objekt gespeichert werden. Als Faustregel kann man davon ausgehen, dass für jede virtuelle Basisklasse, die nicht indirekt vererbt wird, im abgeleiteten Objekt ein zusätzlicher Zeiger existiert, der während der Konstruktion automatisch initialisiert wird.Mit ein bisschen Voodoo, kann man den Cast doch noch durchführen, im Zweifelsfall sollte aber eher das Design überdacht werden. Voraussetzung hierfür ist, dass der vollständige Typ des Objektes bekannt ist, und ein Objekt dieses Typs angelegt wurde. Da alle vollständigen Objekte das gleiche Layout haben, können wir ansetzen:
Derived* virtual_downcast(Base* p) { static complete_type prototype(...); static const std::diffptr_t delta = reinterpret_cast<char*>( &prototype ) - reinterpret_cast<char*>( static_cast<Base*>( &prototype ) ); return reinterpret_cast<complete_type*>( reinterpret_cast<char*>( p ) + delta ); }Sieht böse aus, ist es auch.
-
sowas ähnliches dachte ich mir bereits

in meinem fall ist aber der vollständige typ von
derived
bekannt.struct Interface { virtual void func() = 0; }; struct SpecialInterface : virtual public Interface { virtual void foo() = 0; }; ///////////////////////////////////////////////////////// class Impl : virtual public Interface { public: void func(); // nicht abstrakt, implementationsklasse }; class SpecialImpl : virtual public SpecialInterface, public Impl { public: void foo(); }; void do_something(SpecialInterface *ptr) { // hier ist der vollständige typ von SpecialImpl bekannt. // ptr ist zu 100% ein SpecialImpl! SpecialImpl *impl = static_cast<SpecialImpl *>(ptr); // erlaubt? } int main() { SpecialInterface *ptr = new SpecialImpl; do_something(ptr); delete ptr; }in diesem A B C D diagramm (b und c erben von a, d von b und c)
möchte ich nicht von A nach D, sondern von B nach D.
alle typen sind vollstädnig bekannt.afaik muss
static_castevtl beim cast von D nach B den this-pointer
verändern, je nachdem wo B liegt. dieser offset muss compiletime-konstant
sein, da die klassen sich nicht ändern.jetzt möchte ich nur den umgekehrten weg gehen. B -> D. B ist ein D.
natürlich könnte man den voodoo-hack nehmen (:D) und einfach den offset abziehen,
aber kannstatic_castdas nicht auch?
-
warum benutzt du hier die virtuelle Vererbung? Das Ding kommt eigentlich nie(!) vor. Außer natürlich, du hast ein schlechtes Design (wie zum Beispiel nen kombinierten input/outputstream *hust*)
-
cast-spaß schrieb:
afaik muss
static_castevtl beim cast von D nach B den this-pointer
verändern, je nachdem wo B liegt. dieser offset muss compiletime-konstant
sein, da die klassen sich nicht ändern.jetzt möchte ich nur den umgekehrten weg gehen. B -> D. B ist ein D.
natürlich könnte man den voodoo-hack nehmen (:D) und einfach den offset abziehen,
aber kannstatic_castdas nicht auch?Niemand teilt static_cast den vollständigen Typ mit, also nein. Die einzige Möglichkeit, die mir auf Anhieb einfällt, ist das Offset explizit in den Quellcode zu schreiben und dann bei der Ausführung zu testen, ob der Wert stimmt, oder ggf. beim Konfigurieren des Projekts ein kleines Script auszuführen, dass diesen Wert ermittelt und diesen beim Compilieren weiterzugeben.
Warum hier virtuelle Vererbung zwischen SpecialInterface und SpecialImpl benutzt wird, erschließt sich mir ebensowenig wie otze.
-
weil ich damit erzwinge, dass die konkrete funktion die abstrakte überschreibt,
und nicht anderherum. habe ich vor langer zeit herausgefunden, und seitdem
immer für interfaces genommen.ich möchte auch wirklich nur ein objekt der basisklasse.
-
Ahh ich sehs grad...dein Design ist wahrscheinlich ziemlich wirr...
Das Poblem ist, dass du SpecialImpl von Impl erben lässt...das ist meistens nicht gut.
-
warum sollte das nicht gut sein?
ich vermeide so das erneute definieren von jeweils 5 funktionen in ~70 klassen.
das bringt schon etwas.
-
cast-spaß schrieb:
ich vermeide so das erneute definieren von jeweils 5 funktionen in ~70 klassen.
das bringt schon etwas.Wär das nicht ein Fall von: das gehört ins Interface, weil es eh in allen Klassen gleich ist?
C++ ist nicht Java.
-
otze schrieb:
cast-spaß schrieb:
ich vermeide so das erneute definieren von jeweils 5 funktionen in ~70 klassen.
das bringt schon etwas.Wär das nicht ein Fall von: das gehört ins Interface, weil es eh in allen Klassen gleich ist?
C++ ist nicht Java.
java *igitt*
Ist ja auch alles im Interface, aber die vererbungshierachie der Interfaces
möchte ich auch in der klassenstruktur nachbilden. d.h.klassen | interface | CA <-|- A | | | v | v CB <-|- B | | | v | v CC <-|- CA, B und C sind die interfaces. ich kenne genug libarys, deren öffendliche
schnittstelle auf vererbung basiert.die einzige gute möglichkeit ist halt die mehrfachvererbung.
ich hatte es auch schon mal mit class-chaining versucht, via templates.
aber das war eine katastrophe, sprich _nicht_ schön.
-
ich bins nochmal

// öffentliches interface struct Base { virtual void func() = 0; }; struct Interface : virtual public Base //// <-- ES GEHT UM DAS VIRTUAL HIER { virtual void specialfunc() = 0; }; //////////// ab hier die implemenatation class CBase : virtual public Base { void func(){} }; class CInterface : virtual public Interface, public CBase { void specialfunc(){} }; int main() { CInterface *ptr = new CInterface; Interface *iptr = ptr; Base *b = iptr; Interface *iptr2 = static_cast<Interface *>(b); // geht nicht :( }mit dem virtual kann er nicht von
Base *zuInterface *
koonvertieren, ohne virtual überschreibt meine funktion das interface
nicht, und die funktion ist immer noch abstrakt.wie kann ich das umgehen? ab besten ohne solche haXXs, das muss doch gehen.
ohne dynmaic_cast
MfG cast-spaß
-
Nein, virtual macht dir alles kaputt.
-
Warum willst du eigentlich keinen dynamic_cast verwenden?
-
es ist zu langsam.
grade die msvc-implementierung ist eine katastrophe. irgentwo meine ich
gelesen zu haben, dass die funktion klasseninfos aus der .exe liest.meine jetzige lösung ist eine virtuelle methode in dem interface, void *Downcast()
der teil ist wirklich performancekritisch und wird tausende male aufgerufen