Zeiger von abgeleiteten Klassen mit gleicher Adresse
-
Wenns unbedingt sein muss, machste halt ein Cast..
-
Zunächst einmal, Finger weg von Unions. Merk dir am besten einfach, daß Unions nur POD-Typen (int, float, etc.) enthalten dürfen, aber keine Klassen (Ausnahmen gibt es zwar, die tun hier aber nichts zur Sache). Und fast immer gibt es bessere Lösungen als Unions.
Wenn du in einem Vektor Objekte von mehreren verschiedenen Klassen speichern möchtest, die alle eine gemeinsame Basisklasse haben, dann solltest du einen
std::vector<Base *>verwenden, und die Objekte selbst mitnewallokieren.Außerdem wirfst du in deinem Text ein bißchen Objekte und Zeiger durcheinander. Ein Objekt hat immer nur einen Typ, entweder Base oder Derived, egal welche Sorte von Zeiger du gerade auf das Objekt hältst. Wenn du wirklich von
Base*nachDerived*casten mußt, dann wäredynamic_castdas Stichwort. Aber auch da gilt wieder, daß das bei einem sauberen Design in den wenigsten Fällen nötig sein sollte.
-
Dein Text und dein Code widersprechen sich. Im Text redest du davon, dass du den Zeiger auf die abgeleitete Klasse in einen Zeiger auf die Basisklasse verändern möchtest, im Code zeigst du uns dann schön die andere Richtung. Die Basisklasse ist die, von der du ableitest. Die abgeleitete Klasse entsteht durch Ableitung aus einer Basisklasse.
Was du möchtest, ist ein Cast, der potenziell nur für eine kleine Anzahl von Zeigern auf die Basisklasse gültig ist. Jede "abgeleitete Klasse" ist auch eine "Basisklasse", aber der Umkehrschluss ist natürlich nicht gültig, sobald du die Basisklasse auch separat verwendest oder mehrere verschiedene Klassen von der Basisklasse abgeleitet sind.
Zu diesem Zweck bietet C++ den dynamic_cast, welcher entweder einen gültigen Zeiger zurückliefert, falls der Cast gültig war, oder einen Null-Zeiger. Dieser Cast wird erst während der Laufzeit durchgeführt und ist natürlich ziemlich aufwendig, weil dafür für alle Objekte zur Laufzeit deren Typinformation benötigt wird und verglichen werden muss (Bei allen anderen Casts ist das nicht nötig, weil dort schon während der Compilierzeit die Gültigkeit überprüft werden kann oder erst gar keine Überprüfung stattfindet).Viele Grüße,
Michael
-
Vielen Dank erst mal für die schnellen Antworten.
Wenn ich einen Vektor std::vector<Base *> erstelle und dort dann per Polymorphie verschiedene abgeleitete Objekte "reinstecke", dann kann ich mit dynamic_cast nur das abgeleitete Objekt bekommen, wenn es auch wirklich auf diese abgeleitete Klasse zeigt. Es wäre sehr bequem, wenn ich die Objekte in dem Vektor beliebig in andere Typen konvertieren könnte, allerdings so, dass ich trotzdem auf den gleichen Ort zeige und direkt darauf zugreifen kann. Ich halte es inzwischen allerdings unwahrscheinlich, dass das möglich ist.
Ich werde es also so machen, wie ihr vorgeschlagen habt. Das ist natürlich ein wenig umständlicher.Decimad schrieb:
Dieser Cast wird erst während der Laufzeit durchgeführt und ist natürlich ziemlich aufwendig, weil dafür für alle Objekte zur Laufzeit deren Typinformation benötigt wird und verglichen werden muss.
Ich kenne den dynamic_cast erst seit kurzer Zeit und ich wollte mal fragen, ob es sich nun lohnt, ihn zu benutzen, da er ja anscheinend etwas Zeit verbraucht. Mit unionen, so würde ich vermuten, geht es schneller. Man muss dabei natürlich aufpassen, welche Variable man nun benutzt

-
King_Luc schrieb:
Base b; Derived *pD; pD = &b; //dies gibt einen Fehler und soll nur grob verdeutlichen, was ich meinePolymorphie hat den Sinn, einen Zeiger oder eine Referenz auf eine Basisklasse zu haben, der/die generische Funktionalität besitzt. Das heisst, hinter dem Zeiger/der Referenz muss sich nicht umbedingt tatsächlich eine Basisklasse befinden; eine abgeleitete ist auch möglich. Was du versuchst, ist jedoch das Umgekehrte.
King_Luc schrieb:
Es wäre sehr bequem, wenn ich die Objekte in dem Vektor beliebig in andere Typen konvertieren könnte, allerdings so, dass ich trotzdem auf den gleichen Ort zeige und direkt darauf zugreifen kann. Ich halte es inzwischen allerdings unwahrscheinlich, dass das möglich ist.
Du kannst die Zeiger schon so hinbiegen, dass sie auf irgendein Objekt zeigen. Nur führt das weder zu definiertem Verhalten noch hat es sonst einen Sinn.
King_Luc schrieb:
Ich kenne den dynamic_cast erst seit kurzer Zeit und ich wollte mal fragen, ob es sich nun lohnt, ihn zu benutzen, da er ja anscheinend etwas Zeit verbraucht. Mit unionen, so würde ich vermuten, geht es schneller. Man muss dabei natürlich aufpassen, welche Variable man nun benutzt

Du solltest erst auf Performance achten, wenn du wirklich merkst, dass es nötig ist. Wie gesagt, benutze keine Unions in C++. Für Non-PODs geht das sowieso nicht, und selbst für PODs wirst du sie kaum brauchen.
Unabhängig davon ist auch
dynamic_castnicht eine sehr schöne Lösung. Das meiste kann man mit virtuellen Funktionen erreichen.
-
Der dynamic-Cast ist ja etwas vollständig anderes als Unions. Bei Unions hast du unterschiedliche Objekte an ein und derselben Stelle zu unterschiedlichen Zeiten im Speicher während sich der Dynamic-Cast auf Klassenhierarchien bezieht. Unions verwendet man daher an Stellen, wo die einzelnen Objekte aber auch wirklich gar nichts miteinander zu tun haben (Und dann ist fraglich, warum sie überhaupt an einer Stelle stehen sollen), dynamic_cast's, wo man, für ansonsten über Basisklassen angesprochene Objekte, irgendwann doch mal als Spezialfall eine Sonderbehandlung braucht (beispielsweise um dynamische Dinge benutzerfreundlicher darzustellen, ohne die Basisklassenschnittstelle für einen Typ unnötig aufzuplustern. Naja, zumindest handhabe ich das so

Während du einen Zeiger durch eine Klassenhierarchie castest, bleibt der Zeiger vom Wert her (also der Addresse im Speicher) nicht zwangsweise (oder eher selten) gleich!
-
King_Luc schrieb:
Es wäre sehr bequem, wenn ich die Objekte in dem Vektor beliebig in andere Typen konvertieren könnte, allerdings so, dass ich trotzdem auf den gleichen Ort zeige und direkt darauf zugreifen kann.
Da stellt sich doch erstmal die Frage, warum die Objekte dann überhaupt von verschiedenen Klassen sind. Wenn die Objekte einander so ähnlich sind, daß sie beliebig hin- und herkonvertiert werden können, warum gehören sie dann nicht auch alle zu ein und derselben Klasse?
-
King_Luc schrieb:
Ich habe eine Klasse von einer anderen abgeleitet und nun von der abgeleiteten Klasse einen Zeiger erstellt. Diesen möchte ich nun auf ein Objekt der Basisklasse zeigen lassen, wobei ich auch nur die Eigenschaften der Basisklasse benutzen möchte. Der Zeiger soll vollen Zugriff auf die Funktionen und Variablen des Objekts der Basisklasse besitzen.
Dies geht grundsätzlich nicht, und macht auch keinen Sinn. Das hat alleine schon mit dem Speicherlayout zu tun. Wenn du ein Objekt der Basisklasse auf einen Zeiger auf eine davon Abgeleitete Klasse umbiegst (C-Cast und reinterpret_cast sollten das an sich ermöglichen), so ist ein Zugriff auf diesen Zeiger schlicht und ergreifend kritisch zu nennen.
Was soll bitteschön passieren, wenn du auf eine Methode/Member zugreift die nicht zu der Basisklasse gehört? Das Verhalten ist undefiniert. Es könnte deine Festplatte formatieren, einfach nur einen dahinterliegenden Speicherbereich als Wert interpretieren...
Basisklassen dienen nicht dazu auf untergeordnete Klassen zu verweisen, sondern um als gemeinsame Schnittstelle von davon abgeleiteten zu dienen.
Davon abgesehen noch ein paar andere Punkte:
a) Zugriffsmodifikatoren hast du wohl in der Eile vergessen (public:...)
b) Ich würde Membervariablen möglichst nicht öffentlich deklarieren, selbst Setter/Getter die nichts anderes als den Zugriff weiterleiten haben einen Vorteil: Du kannst später noch einen Zugriffsschutz oder Bereichsüberprüfungen ohne große Codeänderung einfügen.
c) Basisklassen sollten im Regelfall immer über einen virtuellen Destruktor verfügen.cu André
-
asc schrieb:
c) Basisklassen sollten im Regelfall immer über einen virtuellen Destruktor verfügen.
... wenn sie in polymorphen Kontexten benötigt werden.

-
Nexus schrieb:
asc schrieb:
c) Basisklassen sollten im Regelfall immer über einen virtuellen Destruktor verfügen.
... wenn sie in polymorphen Kontexten benötigt werden.

Was zumindestens bei mir der Regelfall ist (und ansonsten sollte man wenigstens die Regel mit dem private-Konstruktor einhalten, den unbedachtes "Vergessen" ist nicht unüblich...).
-
drakon schrieb:
Wenns unbedingt sein muss, machste halt ein Cast..
http://www.c-plusplus.net/forum/viewtopic-var-t-is-229749.html

-
Ok ich werd's jetzt ganz normal über Polymorphie machen.
Am Anfang hatte ich nur eine Klasse, was natürlich kein Problem war. Da ich aber meistens von diesem Typ nur grundlegende Variablen und Funktionen benutzt habe, habe ich noch eine Basisklassse erstellt, die wirklich nur diese paar Variablen erhählt, um nicht so viel Speicher zu verbrauchen. Daraus ergab sich das Problem mit dem Vektor. Ein Freund von mit hat mir Union vorgestellt, was mir da als eine ganz sinnvolle Möglichkeit hielt (ich kannte den dynamic_cast noch nicht). Anscheinend sind diese wohl nicht sinnvoll, also muss ich mein Programm umwandeln.Inzwischen ist mir aufgefallen, dass es nicht viel aufwendiger ist, und dass es wirklich keinen Sinn hat, teilweise auf Eigenschaften eines Objekts zugreifen zu wollen, die dieses eigentlich nicht besitzt.
Danke für die vielen und hilfreichen Antworten!
-
.
(EDIT: hat sich erledigt - hätte erstmal das letzte posting lesen sollen *pfeiff*)
-
mammamia;