Verschiedene Objekte innerhalb eines Vectors unterscheiden
-
--- Huch. Mal wieder auf "antworten" statt "editieren" geklickt ---
Und was glaubst Du, wie ein std::vector funktioniert? Das push_back erwartet eine Referenz auf ein Person-Objekt. Das, was der Vektor dann macht, ist, ein neues Person-Objekt per Kopierkonstruktor zu erstellen. Das neue Objekt ist hinterher nie ein Worker. Genauso speichert ein std::vector<int> nur int-Objekte, die durch das Kopieren erzeugt werden. Damit Laufzeitpolymorphie funktioniert, musst Du indirekt arbeiten => Zeiger (bzw Referenzen).
-
Okay, danke. Ich hab es jetzt mit Zeigern gemacht und einer virtuellen Ausgabemethode:
std::vector<Person*> myPersons; Person* p1 = new Person(); p1->init("Hans", 50, 1.79); myPersons.push_back(p1); Worker* w1 = new Worker(); w1->init("Didi", 44, 1.69, 2000); myPersons.push_back(w1); Child* c1 = new Child(); c1->init("Susi", 10, 1.35, 7); myPersons.push_back(c1); for(unsigned int i = 0; i < myPersons.size(); i++){ myPersons[i]->ausgabe(); }Ausgabe:
Mein Name ist Hans, ich bin 50 Jahre alt und 1.79m groß.
Mein Name ist Didi, ich bin 44 Jahre alt, 1.69m groß und verdiene 2000 Euro.
Mein Name ist Susi, ich bin 10 Jahre alt, 1.35m groß und habe 7 Freunde.Ist das jetzt korrekt von der Vorgehensweise ?
Viele Grüße
-
scrabbl schrieb:
Ist das jetzt korrekt von der Vorgehensweise ?
Was die Polymorphie angeht, ja.
Aber:-
Die init()-Methode ist kein gutes Design. Für sowas sind Konstruktoren da. Was passiert wohl, wenn man mal vergisst, das init für ein Objekt aufzurufen? Richtig, du hättest eine Person ohne Namen, Alter und Größe.
-
Wenn du mit new() allokierte Objekte in deinem vector speicherst, musst du auch dran denken, sie wieder freizugeben, da du sonst Speicherlecks erhälst. Es gibt dafür auch in den boost-Beibliotheken extra Container, die das für dich übernehmen, alternativ kann man auch Smartpointer benutzen, aber das sind schon etwas fortgeschrittene Konzepte. Für den Anfang ist es vielleicht vom Lerneffekt her sogar besser, immer dran zu denken, dass die Dinger auch wieder freigegeben werden müssen.
-
-
pumuckl schrieb:
- Die init()-Methode ist kein gutes Design. Für sowas sind Konstruktoren da. Was passiert wohl, wenn man mal vergisst, das init für ein Objekt aufzurufen? Richtig, du hättest eine Person ohne Namen, Alter und Größe.
Das stimmt, dazu hab ich jetzt aber noch eine Frage. Wenn ich die init-Methoden wegwerfe und es über die Konsruktoren machen, hab ich in der Basisklasse Person einen Konstruktor der Name, Alter und Größe entgegennimmt.
In der abgeleiteten Worker Klasse einen der Name, Alter Größe und Gehalt entgegennimmt. Hier wirft mir der Compiler einen Fehler das der Worker Konstruktor "no matching function in Person::Person" hätte.
Das liegt wohl daran das bei abgeleiteten Klassen zuerst der Konstruktor der Basisklasse aufgerufen wird und dann erst der eigene und dann passt es ja nicht zusammen.
Wenn ich in der Basisklasse jetzt einfach einen zweiten, leeren Konstruktor hinzufüge geht das Ganze fehlerfrei. Ist das die normale Vorgehensweise ?
-
zeig mal deinen Code. Das hört sich alles sehr seltsam an.
Normalerweise ist es kein Problem, dass der Konstruktor einer abgeleiteten Klasse mehr Argumente bekommt, als der Konstruktor der Basisklasse. Dies ist sogar ein recht häufiger Fall.
Felix
-
Du musst den Konstruktor der Basisklasse selbst aufrufen.
-
314159265358979 schrieb:
Du musst den Konstruktor der Basisklasse selbst aufrufen.
Wenn du ihm noch die Begriffe "Basisinitialisierung" und "Initialisierungsliste" gibts, kann er auch was damit anfangen.
-
scrabbl schrieb:
std::vector<Person*> myPersons; Person* p1 = new Person(); p1->init("Hans", 50, 1.79); myPersons.push_back(p1); Worker* w1 = new Worker(); w1->init("Didi", 44, 1.69, 2000); myPersons.push_back(w1); Child* c1 = new Child(); c1->init("Susi", 10, 1.35, 7); myPersons.push_back(c1); for(unsigned int i = 0; i < myPersons.size(); i++){ myPersons[i]->ausgabe(); }Ist das jetzt korrekt von der Vorgehensweise ?
Kommt drauf an, was es werden soll und ob Du es für OK hältst, die Objekte nicht zu löschen.
Oft kommt es mir so vor, als werden bei solchen Beispielen Klassen für etwas missbraucht, was lieber (ggf änderbare) Eigenschaften hätten sein sollen. Ein "Child" wird im erwachsenen Alter nicht unbedingt arbeitslos bleiben.
Neben der Lebenszeit/Specherleckproblematik ist hier die Modellierung meiner Meinung nach fragwürdig. Man sollte sein Design daran ausrichten, wie verschiedene Dinge verwendet werden. Vererbung mit polymorphen Basisklassen setze ich so gut wie nie persönlich ein. Aber hin und wieder kommt es dann mal vor, dass irgendein Programmmodul eine Menge von verschiedenartigen Objekten gleich behandeln muss und/oder im Sinne einer abstrakten Callback-Schnittstelle Daten austauschen will/muss.
-
Person.h
class Person { protected: std::string name; int age; double size; public: //Person(){}; Person(std::string _name, int _age, double _size); virtual ~Person(){} virtual void ausgabe(); };Person.cpp
#include "Person.h" Person::Person(std::string _name, int _age, double _size) { name = _name; age = _age; size = _size; } void Person::ausgabe(){ std::cout << "Mein Name ist " << name << ", ich bin " << age << " Jahre alt und " << size << "m groß." << std::endl; }Worker.h
#include "Person.h" class Worker : public Person{ private: int gehalt; public: Worker(std::string _name, int _age, double _size, int _gehalt); void ausgabe(); };Worker.cpp
#include "Worker.h" Worker::Worker(std::string _name, int _age, double _size, int _gehalt){ name = _name; age = _age; size = _size; gehalt = _gehalt; } void Worker::ausgabe(){ std::cout << "Mein Name ist " << name << ", ich bin " << age << " Jahre alt, " << size << "m groß und verdiene " << gehalt << " Euro." << std::endl; }Mehr ist es eigtl gar nicht. Und der Konstruktor des Workers sagt mir er würde keine "matching function" finden. Sobald ich den auskommentierten, leeren Konstruktor wieder dazunehme geht es einwandfrei.
Über die Sinnhaftigkeit des Beispiels kann man bestimmt streiten. Hab mir das so nicht ausgedacht, stammt aus einem der unzähligen online Tutorials

-
Genau das, was PI gemeint hat und was siebenschwein geschrieben hat: Such mal im Netz (oder im C++-Einsteigerbuch deiner Wahl) nach "Initialisierungsliste".
Dann kommst du auch drum herum, die Attribute von Person als protected zu deklarieren sondern kannst sie wie es sich meist gehört wieder private machen
