vector<class*> list
-
Moin,
ich habe eine parent Klasse "E_Bike" und drei abgeleitete Klassen "E_CityBike", "E_Crossbike" und "E_Pedelec.
Die unterschiedlichen Klassen möchte ich in einer vector-list speichern.vector<E_Bike*> bikes; //use parent??!!
Das klappt soweit auch gut.
Wie bekomme ich jetzt aber innerhalb einer Schleife über alle Elemente der liste zugriff auf spezifische Funktionen der abgeleiteten Klassen?for (unsigned int i = 0; i < bikes.size(); ++i) { bikes[i]->printDataset(); }
Hier wird jetzt immer "nur" die Funktion E_Bike::printDataset() aufgerufen.
Obwohl printDataset in jeder abgeleiteten Klasse überschrieben wurde.Gruß
Marco
-
Ist die Funktion
E_Bike::printDataset()
virtual?
-
Nein
-
Problem gelöst!!
virtual hat geholfen!!Danke dir!
-
Ich habe noch ein weiteres Problem.
ich habe eine parent Klasse "E_Bike" und drei abgeleitete Klassen "E_CityBike", "E_Crossbike" und "E_Pedelec.
Die unterschiedlichen Klassen möchte ich in einer vector-list speichern.Jetzt möchte ich auswahlbasiert neue Objekte dieser Klassen anlegen.
Dabei möchte ich sowohl die Funktionen der Basis-Klasse "E_Bike" als auch auf die Funktionen der abgeleiteten Klassen.class E_Bike { private: unsigned int index = 0; string type; string manufacturer; string mdl; string maxSpeed; string registration; string tirePressure; string akku; public: E_Bike(); virtual ~E_Bike(); void setIndex(unsigned int index) { E_Bike::index = index; } unsigned int getIndex() { return index; } void setType(string type) { E_Bike::type = type; } string getType() { return type; } void setManufacturer(string manufacturer) { E_Bike::manufacturer = manufacturer; } string getManufacturer() { return manufacturer; } void setMdl(string mdl) { E_Bike::mdl = mdl; } string getMdl() { return mdl; } void setMaxSpeed(string maxSpeed) { E_Bike::maxSpeed = maxSpeed; } string getMaxSpeed() { return maxSpeed; } void setRegistration(string registration) { E_Bike::registration = registration; } string getRegistration() { return registration; } void setTirePressure(string tirePressure) { E_Bike::tirePressure = tirePressure; } string getTirePressure() { return tirePressure; } void setAkku(string akku) { E_Bike::akku = akku; } string getAkku() { return akku; } virtual void printDataset(); };
void DB::newDataset(string type) { if (type == "E_CityBike") { E_CityBike* b = new E_CityBike(); b->setIndex(index); b->setType(key_type); b->setManufacturer(key_manufacturer); b->setMdl(key_mdl); b->setMaxSpeed(key_maxSpeed); b->setRegistration(key_registration); b->setTirePressure(key_tirePressure); b->setAkku(key_akku); string key_porter; cout << "Porter: "; cin >> key_porter; b->setPorter(key_porter); cout << "\n"; bikes.push_back(b); listeDatasets(); } if (type == "E_CrossBike"){ E_CrossBike* b = new E_CrossBike(); b->setIndex(index); b->setType(key_type); b->setManufacturer(key_manufacturer); b->setMdl(key_mdl); b->setMaxSpeed(key_maxSpeed); b->setRegistration(key_registration); b->setTirePressure(key_tirePressure); b->setAkku(key_akku); string key_suspension; cout << "Suspension: "; cin >> key_suspension; b->setSuspension(key_suspension); cout << "\n"; bikes.push_back(b); listeDatasets(); } if (type == "E_Pedelec") { E_Pedelec* b = new E_Pedelec(); b->setIndex(index); b->setType(key_type); b->setManufacturer(key_manufacturer); b->setMdl(key_mdl); b->setMaxSpeed(key_maxSpeed); b->setRegistration(key_registration); b->setTirePressure(key_tirePressure); b->setAkku(key_akku); string key_license; cout << "License: "; cin >> key_license; b->setLicense(key_license); cout << "\n"; listeDatasets(); } }
Momentan lege ich die Variable b dreimal an, je nachdem von welchem Typ das Rad ist.
Das führt dann dazu, dass ich auch die Funktionen der Basisklasse drei mal Programmiert habe.Das muss doch auch irgendwie einfacher gehen.
Kann mir hier jemand einen Tipp geben?Gruß
Marco
-
Wo kommen eigentlich die Daten, wie z.B. "index" her? Ok, ist hier nicht die Frage.
Du kannst doch auch in einen Zeiger von Oberklasse "E_Bike" das erstellte Objekt der jeweiligen Unterklasse haben. In der Auswahl, wo du das spezifische Bike erstellst, kannst Du die spezifischen Daten einfügen, den Oberklassenzeiger setzen und ganz zuletzt einmalig die Daten der Oberklasse setzen.
Und wenn Du auch das Pedelec im Conteiner haben möchtest, kannst Du den Oberklassenzeiger Zeiger einfügen.BTW. Schau mal nach Smart-Pointer.
-
E_Bike* b = new E_Bike(); if (type == "E_Pedelec") { E_Pedelec* b = new E_Pedelec(); b->setLicense(key_license); } b->setIndex(index); b->setType(key_type); b->setManufacturer(key_manufacturer); b->setMdl(key_mdl); b->setMaxSpeed(key_maxSpeed); b->setRegistration(key_registration); b->setTirePressure(key_tirePressure); b->setAkku(key_akku); bikes.push_back(b);
Das führt dazu, dass ein Pointer auf ein Objekt der Klasse "E_Bike" und nicht "E_Pedelec" im Vector abgelegt wird.
------------------------- Datasets count = 1 ------------------------- Index: 1 Type: dd Manufacturer: dd MDL: dd Max. Speed: dd Registration: dd Tire pressure: dd Akku: dd -------------------------
"License" fehlt....
Das Object E_Pedelec ist ja im Scope der IF "gefangen"
-
Kleines Missverständnis. Ich meinte nicht, dass ein E_Bike instantiiert werden sollte, sondern dass das instantiierte E_Pedelec nach dem Setzen seiner spezifischen Daten dem E_Bike zugewiesen wird.
E_Bike* bike = nullptr; if (type == "E_Pedelec") { E_Pedelec* pedelec = new E_Pedelec(); pedelec→setLicense(key_license); bike = pedelec; } bike->setIndex(index); bike->setType(key_type); bike->setManufacturer(key_manufacturer); bike->setMdl(key_mdl); bike->setMaxSpeed(key_maxSpeed); bike->setRegistration(key_registration); bike->setTirePressure(key_tirePressure); bike->setAkku(key_akku); bikes.push_back(bike);
-
Klasse, läuft!
Danke dir!!void DB::newDataset(string type) { unsigned int key_index = 0; string key_type; string key_manufacturer; string key_mdl; string key_maxSpeed; string key_registration; string key_tirePressure; string key_akku; ++index; cout << "\nPlease enter general data:\n"; cout << "Type: "; cin >> key_type; cout << "Manufacturer: "; cin >> key_manufacturer; cout << "MDL: "; cin >> key_mdl; cout << "Max. Speed: "; cin >> key_maxSpeed; cout << "Registration: "; cin >> key_registration; cout << "Tire pressure: "; cin >> key_tirePressure; cout << "Akku: "; cin >> key_akku; E_Bike* e_bike = nullptr; if (type == "E_CityBike") { E_CityBike* e_cityBike = new E_CityBike(); e_cityBike->setBikeClass("E-CityBike"); string key_porter; cout << "Porter: "; cin >> key_porter; e_cityBike->setPorter(key_porter); cout << "\n"; e_bike = e_cityBike; } if (type == "E_CrossBike"){ E_CrossBike* e_crossBike = new E_CrossBike(); e_crossBike->setBikeClass("E-CrossBike"); string key_suspension; cout << "Suspension: "; cin >> key_suspension; e_crossBike->setSuspension(key_suspension); cout << "\n"; e_bike = e_crossBike; } if (type == "E_Pedelec") { E_Pedelec* e_pedelec = new E_Pedelec(); e_pedelec->setBikeClass("E-Pedelec"); string key_license; cout << "License: "; cin >> key_license; e_pedelec->setLicense(key_license); cout << "\n"; e_bike = e_pedelec; } e_bike->setIndex(index); e_bike->setType(key_type); e_bike->setManufacturer(key_manufacturer); e_bike->setMdl(key_mdl); e_bike->setMaxSpeed(key_maxSpeed); e_bike->setRegistration(key_registration); e_bike->setTirePressure(key_tirePressure); e_bike->setAkku(key_akku); bikes.push_back(e_bike); listeDatasets(); }
-
Wenn du das Ganze jetzt noch schön machen möchtest implementierst du das in eigenen Funktionen. Außerdem solltest du Eingabe, Objekterzeugung, etc. voneinander trennen und nicht alle in eine Funktion packen.
Und du solltest dir angewöhnen, smart pointer statt besitzender Raw Pointer zu benutzen. Ich sehe in deinem Code mehrerenew
, aber keindelete
. Irgendwann wird das Probleme machen.#include <memory> #include <string> #include <vector> // Smart Pointer kümmert sich um die Lebenszeit der Objekte using IBikePtr_t = std::shared_ptr<E_Bike>; // oder auch std::unique_ptr // konkrete Erzeugerfunktionen in einem anonymen namespace, damit sie den globalen namespace nicht "verschmutzen" namespace { IBikePtr_t create_city_bike() { std::shared_ptr<E_CityBike> retval = std::make_shared<E_CityBike>(); // div. Zuweisungen return retval; } IBikePtr_t create_cross_bike() { std::shared_ptr<E_CrossBike> retval = std::make_shared<E_CrossBike>(); // div. Zuweisungen return retval; } IBikePtr_t create_pedelec() { std::shared_ptr<E_Pedelec> retval = std::make_shared<E_Pedelec>(); // div. Zuweisungen return retval; } } // Erzeugerfunktion erzeugt polymorphe Objekte IBikePtr_t create_bike( std::string const& type ) { if( type == "E_CityBike" ) ) return create_city_bike(); else if( type == "E_CrossBike" ) return create_cross_bike(); else if( type == "E_Pedelec" ) return create_pedelec(); // TO DO: Fehlerbehandlung für unbekannten Typ? // leeren Pointer zurückgeben return IBikePtr_t(); }
-
Hallo @Pf-nne,
ich weiß nicht, aus welchen Motiven Du das Stück Software schreibst. Wenn es keine "Aufgabe" mit Verwendung von Zeigern ist, würde ich Dir gern, wie schon im ersten Post angedeutet, die Verwendung von intelligenten Zeigern an empfehlen.Du verlierst nichts, gewinnst aber viel. Nehmen wir den Kontainer "bikes" mit seinen Zeigern. Ich nehme an, dass es sich wohl um so was wie std::list oder std::vector handelt. Diese zerstören meines Wissens nicht die Objekte der verwalteten Zeiger.
Du müsstest als sicherstellen, das Objekte, welche Du mittels "new"auf dem "Heap" erstellst, auch wieder mittels "delete" aus dem Speicher entfernst. Jedes "new" braucht sein "delete", und nur eins. Das kann in komplexeren Programmen schon mal in die Hose gehen, indem z.B. Speicher nicht mehr freigegeben wird, oder wieder erwarten schon freigegeben wurde. Was habe ich früher Zeit aufgewendet, um dieser Problematik Herr zu werden.
Die Wunderwaffe sind intelligente Zeiger, die wie rohe Zeiger verwendet werden können, aber die Speicherverwaltung übernehmen.
Wenn Dich das Thema interessiert, recherchiere gerne mal nach "Intelligente Zeiger (Modern C++)" mit der Suchmaschine Deiner Wahl.Edit: Sehe gerade, @DocShoe hat schon darauf hingewiesen.
-
Klasse, danke für die Tipps!!
Ich werde das noch ein wenig weiter zerlegen und schaue mir nochmal die smart Pointer an!