dynamische Objekte Teil 2
-
Sorry, aber ich bin schon wieder mit meinem Latein am Ende...
Nach meiner Frage gestern, habe ich heute ein weiteres Problem mit dynamischen Objekten.Ich habe folgende Vererbungsstruktur
class Particle // Attribute double x,y,z class Atom : virtual public Particle // zus. const string &chemElement class Molecule : virtual public Particle // zus. Atom* atoms, int n_atomsund folgendes Beispielprogramm:
int main() { Particle **P = new Particle*[12]; for (int i = 0; i < n_P; i++) // Initialisierung der Particle { double x = 1; double y = 2; double z = 3; Atom atoms[2]; atoms[0] = Atom(x,y,z, "H2"); atoms[1] = Atom(x,y,z, "O"); P[i] = new Molecule (x,y,z, atoms, 2); } // Ausgabe der Particle for (i = 0; i < n_P; i++) { cout << P[i]->toString() << "\n"; } return 0; }Die Elementfunktion toString() sieht im Fall von Molecule so aus:
std::string Molecule::toString() { std::ostringstream os; os << "Molecule ("; for (int i = 0; i < n_atoms; i++) { os << atoms[i].toString() << " "; } os << ")"; return os.str(); }Bei der Ausgabe der Particle wird nun in der Anweisung
atoms[i].toString() //siehe Molecule::toString()nicht die zur Klasse Atom gehörende Elementfuktion toString aufgerufen, sondern die der Basisklasse Particle.
Wenn ich in main aber schreibe:Atom* atoms = new Atom[2]; // anstatt Atom atoms[2];funktioniert es. Und das verstehe ich nicht...
Hoffe, das war genug Text, um das Problem zu verstehen und nicht zu viel, um beim lesen müde zu werden ;).
-
Du musst die Methode in der Basisklasse virtual machen. Eine Verbung die virtual ist, heißt NICHT dass alle Methoden "virtuell" vererbt werden. -> Stichwort Polymorphie.
Gruß
-
FireFlow schrieb:
Du musst die Methode in der Basisklasse virtual machen. Eine Verbung die virtual ist, heißt NICHT dass alle Methoden "virtuell" vererbt werden. -> Stichwort Polymorphie.
Gruß
...ist in der Basisklasse virtual.
-
Nanuq schrieb:
...ist in der Basisklasse virtual.
Deshalb musst du nicht virtuell vererben. Momentan würde das nur Sinn machen, wenn du eine Klasse hast, die sowohl von Atom als auch Molecule erbt. Sinnvoll ist sowas imo nicht.
-
...damit nicht mehrere Subojekte von Particle in einer von Molecule und Atom abgeleiteten Klasse entstünden.
Ist noch recht neu für mich, da kommt es schon mal zu solchen Unsicherheiten
.An meiner eigentlichen Frage ändert es aber trotzdem nichts. Ich verstehe nicht, was es hier für einen Unterschied macht, ob ich
Atom atoms[2];oder
Atom* atoms = new Atom[2];schreibe.
Ist nicht der Zeiger, den ich (innerhalb des selben Blocks)P[i] = new Molecule (x,y,z, atoms, 2);übergebe, in beiden Fällen derselbe?
(Übrigens stammt die komplette Aufgabe von hier: http://www.lrz-muenchen.de/~ebner/C++/Uebung/aufgaben_004.html . Dort enthält die Aufgabenstellung genau diesen "Fehler", während er - leider ohne Erklärung :(- im Lösungsvorschlag korrigiert ist)
-
Im ersten Fall ist atoms ein Array auf dem Stack der Funktion, der seine Gültigkeit beim "}" der for-Schleife verliert (wenn Du in new Molecule nur den Zeiger übernimmst), demzufolge dürften alle deine Moleküle auf dieselben beiden Atome verweisen, die immer wieder initialisiert werden (und selbst das ist unvorhersehbar)...
Im zweiten Fall erzeugst Du jedesmal ein neues Paar Atome auf dem Heap und übernimmst es in dein Molekül, was schonmal zumindest korrekt und überdies sauberer ist

EDIT: Achja, während ersteres beim "}" seine Gültigkeit verliert muss zweiteres natürlich irgendwo aufgeräumt werden mittels delete[]

-
@Nanuq
Technisch besteht der Unterschied nur darin, dass einmal automatischer Speicher und einmal Freispeicher verwendet wird. Praktisch bedeutet das, dass beide Objektarrays gleichermassen benutzt werden können. Bei der dynamischen Version muss jedoch noch manuell delete[] aufgerufen werden. Sofern du in Molecule Kopien der Atome erzeugst, sollte es so problemlos funktionieren.
Ansonsten kann ich dein Problem ehrlich gesagt nicht nachvollziehen. Zeig mal Deklaration und Definition von Particle::toString und Atom::toString.
-
groovemaster schrieb:
Zeig mal Deklaration und Definition von Particle::toString und Atom::toString
std::string Particle::toString() { std::ostringstream os; os << "Particle [" << std::setprecision(3) << x << "," << y << "," << z << "]"; return os.str(); } std::string Atom::toString() { std::ostringstream os; os << "Atom " << chemElement; return os.str(); }Aber ich denke, ich habe es schon begriffen. Wenn ich mir in Molecule nur die Zeiger merke anstatt Kopien der Werte zu erstellen, ist die Information bei } verloren. Wenn ich z.B. die Ausgabe noch vor dem Ende des Blocks (innerhalb der Schleife) durchführe funktioniert es ebenfalls.
Prinzipiell ist mir die Sache mit Stack und Heap sowie new und delete schon klar, denke ich, allerdings schleichen sich bei der Anwendung doch immer wieder Denkfehler ein.
Naja, Übung macht den Meister
Danke jedenfalls euch beiden!