Welcher Cast von void* auf T*
-
dynamic_cast ist um einen zeiger auf eine basisklasse auf einen zeiger auf ein derivat zu casten.
static_cast konvertiert zwischen den datentypen hin und her
und reinterpret_cast interpretiert das an der übergebenen speicheraddresse vorhandene bitmuster als anderen datentypen
-
Bedenke, dass
T* ----------> void* ----------> T* | | static_cast static_cast oder implizitproblemlos so funktioniert, wie man es gerne hätte (verlustfreie Rundreise) wohin gegen so etwas wie
Derived* ----------> void* ----------> Base* (Falsch!) | | static_cast static_cast oder implizitnicht dasselbe ist wie
Derived* --> Base* ----------> void* ----------> Base* (Richtig!) \______ | | \ static_cast static_cast oder implizitMit anderen Worten: Du darfst einen void* nur dorthin zurückkonvertieren, woher er genommen ist (wenn man const und volatile mal ignoriert).
-
Skym0sh0 schrieb:
dynamic_cast ist um einen zeiger auf eine basisklasse auf einen zeiger auf ein derivat zu casten.
Wie
static_castSkym0sh0 schrieb:
static_cast konvertiert zwischen den datentypen hin und her
Wie
const_cast,dynamic_cast,reinterpret_castptr_conversion schrieb:
[...]
Gut erklärt! Als Ergänzung sei vielleicht noch gesagt, dass man
void*relativ selten benötigt. Z.B. für Low-Level-Speicherverwaltung oder als eine Art Type Erasure, die zu weniger Template-Bloat führt (wie z.B. in Boost.PtrContainer).
-
Hallo,
ich habe im Moment auch ein Cast-Problem. Ich schreib es mal hier rein, da es hier eh schon ums Casten geht:Folgendes habe ich (nur beispielhaft):
struct base { int a; } struct derived1 : public base { std::vector<int> b; } struct derived2 : public base { int c; }(in echt sind die Structs natürlich um einiges komplexer und es gibt mehr abgeleitete).
Nun habe ich ein Methode die viele Dateien läd und je nach Informationen in die verschiedenen derived Structs schreibt. Folgendes kommt dann zurück:
std::vector<std::pair<std::string, std::vector<base>>> //std::string ist der Typname, und im Vektor werden alle Struktur-Objekte des Typs gespeichertNach dem mein Hauptprogramm nun die Daten geladen hat und in diesem Konstrukt hat, will es durch diese iterieren und nutzen.
std::vector<std::pair<std::string, std::vector<base>>> resultVector = loadAll(); for(std::vector<std::pair<std::string, std::vector<base>>>::iterator iter = resultVector.start; ...) { for(std::vector<base> iter2 = iter->second.begin(); ...) { if(iter->first == "1") //hier weiß ich, dass es derived1 sein muss else if(iter->first == "2") //hier weiß ich, dass es derived2 sein muss } }Das ist wieder so weit runter gebrochen, dass das wichtigste da ist. z.b. wird normalerweise nicht direkt vorm durch iterieren erst geladen.
So aber jetzt muss ich base nach derived1 casten können und genau das schaffe ich nicht. hab es schon mit dynamic_cast, static_cast und explizite Conversion versucht aber alles klappt nicht.
dynamic_cast will nur derived zu base machen aber nicht umgekehrt.z.B. der static_cast:
derived1* strategy = static_cast<derived1*>(&(*iter2));Kompiliert aber nach dem Casten steht Müll drin.
Wie mache ich es richtig?
Danke für eure Hilfe
-
Hier findet Slicing statt, da du die Objekte per Value in den vector speicherst. Du musst Zeiger verwenden, dafür eignet sich z.B. boost::ptr_vector oder ein std::vector<unique_ptr<T>>.
-
danke
so hats funktioniert. wollte um das "new" rum kommen.Habe nun einen
std::vector<std::pair<std::string, std::vector<base*>>>was haben boost::ptr_vector und std::vector<unique_ptr<T>> für Vorteile?
-
Auch wenn ich etwas zu langsam war:
Kuck dir mal folgendes an:#include <vector> class FooBar{ public: virtual ~FooBar(){} // Deine Basisklasse braucht eine virtuelle Funktion oder Destruktor für einen dynamic_cast }; class Foo : public FooBar{ void foo(){} } class Bar : public FooBar{ void bar(){} }; int main(){ std::vector<FooBar*> vec; // Du brauchst einen Vektor von Pointern, da sonst der Copy-Konstruktor der Basis-Klasse aufgerufen wird - Alle Informationen der abgeleiteten Klassen incl. v-table gehen verloren vec.push_back(new Foo()); vec.push_back(new Bar()); for(std::vector<FooBar*>::const_iterator it = vec.begin(); it!=vec.end(); ++it){ if(Foo* foo = dynamic_cast<Foo*>(*it)){ // so kannst du testen, ob ein Zeiger auf ein Objekt von einem bestimmten Typ ist - dynamic_cast liefert 0, wenn es nicht der Fall ist foo->foo(); } if(Bar* bar = dynamic_cast<Bar*>(*it)){ bar->bar(); } } // Löschen der Objekte nicht vergessen, weswegen sich evtl. ein boost::ptr_vector anbietet, der alle Objekte darin löscht, wenn er zerstört wird (siehe PI) }EDIT: Wenn dynamic_cast ohne Zeiger verwendet wird, fliegt, falls es nicht möglich ist, eine bad_cast Exception.
Gruß,
XSpille
-
Therese schrieb:
was haben boost::ptr_vector und std::vector<unique_ptr<T>> für Vorteile?
Du brauchst dich nicht um das delete kümmern, das wird dann für dich automatisch erledigt.
-
314159265358979 schrieb:
Therese schrieb:
was haben boost::ptr_vector und std::vector<unique_ptr<T>> für Vorteile?
Du brauchst dich nicht um das delete kümmern, das wird dann für dich automatisch erledigt.
Falls du boost verwenden darfst, würde ich boost::ptr_vector verwenden, da std::vector<unique_ptr<T>> afaik keine Vorteile hat (außer dass man 0 drin speichern kann).
-
Im Normalfall besser als std::vector<std::shared_ptr<T>>

Aber ja, boost::ptr_vector ist zu bevorzugen.
-
314159265358979 schrieb:
Im Normalfall besser als std::vector<std::shared_ptr<T>>

Aber ja, boost::ptr_vector ist zu bevorzugen.Bring ihn nicht auf blöde Gedanken mit std::vector<std::shared_ptr<T>>,

sonst ist hier bald wieder jemand neues im Forum, der boost::shared_ptr<T> bzw. std::shared_ptr<T> als universellen 'Problemlöser' nutzt und Overhead in Kauf nimmt, den er in den seltensten Fällen nicht benötigt