Array einer abstrakten Klasse
-
frankne schrieb:
So, aber wie kann ich nun die objekte in dem array speichern und dennoch auf die klassenspezifische draw() funktion zugreifen?
Ich zeige dir hier mal die üblichen C++ Wege, nur damit du dies schon gesehen hast:
1. Es gibt bessere Alternativen als Arrays unter C++ (Sei es std::vector oder falls dein Compiler TR1 unterstützt std::tr1::array)
2. Alle Basisklassen sollten einen virtuellen Destruktor besitzen, passe deine Klasse bitte wie folgt an:class NodeC { public: virtual void draw()=0; virtual ~NodeC() {}; // Bitte in Basisklassen virtuellen Destruktor vorsehen };Da vector auf eigentlich allen Systemen bekannt ist, nehme ich diesen erst einmal als Beispiel (vector kann im gegensatz zum Array und std::tr1::array dynamisch wachsen):
// Ungetestet, kann sein das ich irgendwo einen Fehler habe, dann einfach melden... #include <vector> // #include "Include deiner Klassen"... int main() { std::vector<NodeC*> nodes; // Füllen des vector // Jedes push_back hängt ein Element am Ende an: nodes.push_back(new PolygonC()); nodes.push_back(new TransC()); // Verwendung // Hier zeige ich zwei Varianten, die erste wirst du als Anfänger besser // verstehen. // Verwendung, Variante 1: Über den Index for(int i=0, ende=nodes.size(); i<ende; ++i) nodes[i]->draw(); // Verwendung, Variante 2: Über die Iteratoren // Ich werde hier keine komplette Iteratoreinführung schreiben, stell dir // einen Iterator als ein Element vor das die Position eines Containers // (wie std::vector) hält. Vorteil hierbei ist, das es auch mit Containern // funktioniert, die keinen Wahlfreien Zugriff per Index erlauben: for(std::vector<NodeC*>::iterator it=nodes.begin(), ende=nodes.end(); it!=end; ++it) it->draw(); // Wichtig: Alle Elemente die mit new Alloziert werden, müssen mit delete // Freigegeben werden! for(int i=0, ende=nodes.size(); i<ende; ++i) delete nodes[i]; }Es gibt auch Wege wie die Freigabe automatisiert werden kann, aber verdaue erstmal den Code...
cu André
-
muh schrieb:
NodeC **array; array = new NodeC*[100]; aray[i] = new NodeC();Und hier musst du nun noch mehrere delete Aufrufe (Für die Einzelelemente) und einmal delete[] für das array unterbringen...
Irgendwie hat hier jemand zuviel C, und zuwenig C++ im Hinterkopf.
-
Hallo André,
vielen Dank für deine Anwort! Jetzt habe ich aber noch ein Problem: bisher habe ich ein Objekt erstellt und dann Eigenschaften über den istream operator hinzugefügt etwa so:
CircleC a; iss>>a; node[0]=&a;wie kann ich nun auf die Elemente im Vector den istream operator anwenden?
Cu Frank
-
Auf einen std::vector kannst du das äquivalent anwenden.. (Unterstützt die []-Notation).
-
frankne schrieb:
Jetzt habe ich aber noch ein Problem: bisher habe ich ein Objekt erstellt und dann Eigenschaften über den istream operator hinzugefügt etwa so:
Um Polymorphie verwenden zu können benötigst du Zeiger oder Referenzen. Daher gehe ich den Fall mal mit der dynamischen Speicherverwaltung durch:
Dein Beispiel für ein Objekt
CircleC a; iss>>a; node[0]=&a;Dein Beispiel, angepasst auf dynamische Speicherverwaltung und Zeigerarithmetik):
CircleC* a = new CircleC(); iss >> *a; nodes.push_back(a);Ich hoffe jetzt keinen Fehler gemacht zu haben, da ich (warum auch immer) noch immer tierisch Müde bin...
cu André
-
asc schrieb:
// Verwendung // Hier zeige ich zwei Varianten, die erste wirst du als Anfänger besser // verstehen. // Verwendung, Variante 1: Über den Index for(int i=0, ende=nodes.size(); i<ende; ++i) nodes[i]->draw(); // Verwendung, Variante 2: Über die Iteratoren // Ich werde hier keine komplette Iteratoreinführung schreiben, stell dir // einen Iterator als ein Element vor das die Position eines Containers // (wie std::vector) hält. Vorteil hierbei ist, das es auch mit Containern // funktioniert, die keinen Wahlfreien Zugriff per Index erlauben: for(std::vector<NodeC*>::iterator it=nodes.begin(), ende=nodes.end(); it!=end; ++it) it->draw(); }Wenn schon, denn schon.....

Variante 3: // prefer algorithms calls to hand-written loops (siehe: Scott Meyers, Effective STL, Item 43)
for_each(nodes.begin(), nodes.end(), mem_fun(&Shape::draw));
-
jencas schrieb:
Variante 3: // prefer algorithms calls to hand-written loops (siehe: Scott Meyers, Effective STL, Item 43)
Das Item ist mir bekannt, nur das ich mem_fun & Co grundsätzlich nicht einsetze und boost::bind/std::tr1::bind noch nicht überall verfügbar sind.
Zumal der OT erstmal das Konzept der Iteratoren grob verstehen sollte bevor ich ihn mit den Algorithmen plage

cu André
-
asc schrieb:
Das Item ist mir bekannt, nur das ich mem_fun & Co grundsätzlich nicht einsetze und boost::bind/std::tr1::bind noch nicht überall verfügbar sind.
Naja, zumindest diese Teile von Boost sind überall verfügbar wo der Entwickler einen USB-Anschluss/CD-Laufwerk/Internetanschluss zur Verfügung hat und Dateien ablegen darf.
Dass man es in der Praxis trotzdem nicht jederzeit nutzen kann, ist mir allerdings klar

-
Hi,
sorry habe mich schlecht ausgedruekt,meine eigentliche frage zum input operator war:
wenn ich das hier habenodes.push_back(new PolygonC());wie kann ich mit dem inputoperator auf nodes[0] zugreifen?
ich dachte das hier funktioniert, aber tuts nichiss>>nodes[0];cu frank
-
frankne schrieb:
Hi,
sorry habe mich schlecht ausgedruekt,meine eigentliche frage zum input operator war:
wenn ich das hier habenodes.push_back(new PolygonC());wie kann ich mit dem inputoperator auf nodes[0] zugreifen?
ich dachte das hier funktioniert, aber tuts nichiss>>nodes[0];cu frank
Neee, das geht so nicht. Schau Dir mal das Beispiel hier an: http://www.c-plusplus.net/forum/viewtopic-var-p-is-1613800.html#1613800 (im unteren Teil des Beitrags!)
-
frankne schrieb:
nodes.push_back(new PolygonC()); ... iss>>nodes[0];nodes[0] gibt, da du Zeiger hälst auch einen eben solchen zurück. Und ich nehme einfach mal an das dein Operator für Objekte, nicht für Zeiger definitert ist
(Zudem würde ich diesen wenn für den Basisklassenzeiger definieren, und diesen eine virtuelle Funktion aufrufen lassen).
-
danke für die hilfe, aber bin ich etwas durch durcheinander. du meinst ich soll
iss>>*nodes[0]verwenden und dann eine virtuelle funktion des operator>> in der basisklasse NodeC zur verfügungstellen?
etwa so?class NodeC{ public: virtual void draw()=0; virtual istream& operator>>(istream& s, NodeC& p)=0; virtual ~NodeC()=0; };da kommt der fehler:
NodeC.h `std::istream& NodeC::operator>>(std::istream&, NodeC&)' must take exactly one argument
-
frankne schrieb:
nodes.push_back(new PolygonC());Bist du sicher, dass du die Objekte im Vector dynamisch speichern willst? Container nehmen dir unter anderem diese Arbeit ab. Falls Objekte anstelle von Zeigern auch reichen (weil zum Beispiel der Typ vollständig bekannt ist), empfehle ich sie dir auch. So musst du auf jeden Fall immer an
deletedenken.frankne schrieb:
etwa so?
[...]
da kommt der fehler: [...]Ich würde den
operator>>als globale Funktion deklarieren. Wenn du ihn in der Klasse deklarierst, ist das erste Argument implizit eine Instanz dieser Klasse.
-
Nexus schrieb:
Bist du sicher, dass du die Objekte im Vector dynamisch speichern willst?
Nach seiner Beschreibung würde ich sagen: Ja, da er explizit unterschiedliche Objekte ablegt.
cu André
-
asc schrieb:
Nach seiner Beschreibung würde ich sagen: Ja, da er explizit unterschiedliche Objekte ablegt.
Stimmt, da hast du Recht. Ich dachte nicht mehr daran, dass Polymorphie im Spiel ist.
-
Nexus schrieb:
asc schrieb:
Nach seiner Beschreibung würde ich sagen: Ja, da er explizit unterschiedliche Objekte ablegt.
Stimmt, da hast du Recht. Ich dachte nicht mehr daran, dass Polymorphie im Spiel ist.
Wobei ich die Performance hintenan stelle und in Vektoren trotz allen "Overheads" lieber die shared_ptr verwende

Aber ich glaube wir sollten den OT damit erst belasten wenn er den Rest komplett verarbeitet hat...