Problem bei Polymorphismus mit map<>
-
Guten Morgen,
hier erstmal mein Code:
#include <iostream> #include <map> #include <string> using namespace std; class Basis { public: virtual void reden() { cout<<"Basisklasse"<<endl; } }; class Abgeleitete : public Basis { public: void reden() { cout<<"Abgeleitete Klasse"<<endl; } }; class AbgeleiteteClass2 : public Basis { public: void reden() { cout<<"2. Abgeleitete Klasse"<<endl; } }; int main() { map<string,Basis*> mymap; map<string,Basis*>::iterator iter; Abgeleitete abg; AbgeleiteteClass2 secondabg; mymap["abg"] = &abg; mymap["secabg"] = &secondabg; Basis *base[] ={mymap["abg"],mymap["secabg"]}; // Ab hier wird es interessant, ich bin der Meinung das es so wie es jetzt ist, sehr unsauber ist. for(int i = 0; i<2;i++) { base[i]->reden(); } //Daher brauche ich eurer Hilfe, erklärung folgt unten delete []base; return 0; }
Also mein Problem ist folgendes:
Ich möchte über mein *basis Zeiger alle "reden"-Methoden der sich in der Map befindlichen Unterklassen ansprechen. Jedoch weiß ich nicht wie ich mit der map und wahrscheinlich mit dem map internen Iterator und über den basis zeiger auf diese Methoden zugreifen kann, so das ich dann nur noch eine Schleife habe in der ich dann alabase->reden();
alle reden methoden irgendwie ansprechen kann. Ich hoffe ihr wisst mir zu helfen, weil ich weiß nicht mehr weiter und bin dann nur noch zu diesem unsauberen code gekommen.
Danke
-
So vielleicht?
#include <iostream> #include <string> #include <map> struct Base { virtual foo(){std::cout << "Base\n";} }; struct D1 : public Base { virtual foo(){std::cout << "D1\n";} }; struct D2 : public Base { virtual foo(){std::cout << "D2\n";} }; typedef std::map<std::string, Base*> TestMap; typedef std::map<std::string, Base*>::iterator TestMapIter; int main() { TestMap map; TestMapIter iter; D1 d1; D2 d2; map["D1"] = &d1; map["D2"] = &d2; iter = map.begin(); while(iter != map.end()) { (iter->second)->foo(); ++iter; } return 0; }
-
ja genau das ist das was ich gesucht habe, aber kannst du vieleicht erklären was das ->second ist? Habe hier auch nix vernünftiges zu dem map iterator gefunden:
http://www.cplusplus.com/reference/stl/map/map.htmldaher wäre ich über eine aufklärung sehr interessiert
danke nochmal
P.S. Nochmal als verständnis für mich die methoden die du in den abgeleiteten klassen auf virtual gesetzt hat, muss man ja nicht auf virtual setzen richtig? Weil sie ja in der Basisklasse auf virtual sind und in den abgeleiteten überschrieben werden, habe ich das richtig verstanden?
-
Der Map-Iterator zeigt auf ein Pair. first ist der Schlüssel, second ist der Wert.
-
ahhh ja klar logisch, hätte ich mir auch selber denken können, danke für die Erklärung.
Schönen Tag noch
-
sorry für dopplepost, aber was mich mal noch interessieren würden.
Ist diese Version ordentlich oder könnte man es anders machen, mir ist halt wichtig das es wirklich ordentlich und Stilvoll ist?
-
Firefighter schrieb:
P.S. Nochmal als verständnis für mich die methoden die du in den abgeleiteten klassen auf virtual gesetzt hat, muss man ja nicht auf virtual setzen richtig? Weil sie ja in der Basisklasse auf virtual sind und in den abgeleiteten überschrieben werden, habe ich das richtig verstanden?
Jo. Muss man nicht. Ich war nur faul, und habe Copy and Paste auf Base gemacht.
Firefighter schrieb:
sorry für dopplepost, aber was mich mal noch interessieren würden.
Ist diese Version ordentlich oder könnte man es anders machen, mir ist halt wichtig das es wirklich ordentlich und Stilvoll ist?Wieso willst Du denn eine Map benutzen, wenn Du eh alle Elemente ansprechen willst? Würde sich da ein Vektor nicht besser eignen?
-
Ich wollte mal zum testen mit map arbeiten
aber natürlich wäre vector da besser, ich werde das scenario mit vector mal durchspielen.
Danke!
-
Firefighter schrieb:
Ist diese Version ordentlich oder könnte man es anders machen, mir ist halt wichtig das es wirklich ordentlich und Stilvoll ist?
So wie es Tachyon geschrieben hat ist es sowohl von der Logik wie vom stilistischen her ordenlich.
Das einzige worüber man meines erachtens streiten kann ist eine Kleinigkeit. In der while-schleife wird das "map.end()" mit jedem Durchlauf ausgeführt, ich persönlich ziehe folgenden Code vor:
(Wunder dich nicht, ich arbeite in der Regel erst bei längeren Ausdrücken mit typedef, das ist aber Geschmackssache):
for(std::map<std::string, Base*>::iterator pos = map.begin(), end = map.end(); pos != end; ++pos) { pos->second->foo(); }
Code ist aber ungetestet.
cu André
-
Hi,
ich habe noch zwei Anmerkungen zu "Speicherdingen":
Firefighter schrieb:
...
... Basis *base[] ={mymap["abg"],mymap["secabg"]}; .... delete []base; return 0; }
...
1.) Wo kein new[] da kein delete[].
Mit diesem delete[] zerschießt Du Dir den Speicher, weil Du Speicher auf dem Stack mit dem "Heap-delete" abräumen möchtest.2.) Hier funktioniert diese "Zeigerei", aber mit "Objekten" in einer map (oder einem anderen STLContainer) ist das Halten von Zeigern/Referenzen auf ihre Elemente "kribbelig", weil die Container ihre Objekte verlagern können und damit Deine Zeiger/Referenzen ungültig werden können. Die einzelnen Container haben unterschiedliche "Zusagen über die Haltbarkeit ihrer Iteratoren" ... und das betrifft Zeiger/Referenzen genau so.
Gruß,
Simon2.
-
Simon2 schrieb:
2.) Hier funktioniert diese "Zeigerei", aber mit "Objekten" in einer map (oder einem anderen STLContainer) ist das Halten von Zeigern/Referenzen auf ihre Elemente "kribbelig", weil die Container ihre Objekte verlagern können und damit Deine Zeiger/Referenzen ungültig werden können. Die einzelnen Container haben unterschiedliche "Zusagen über die Haltbarkeit ihrer Iteratoren" ... und das betrifft Zeiger/Referenzen genau so.
Gruß,
Simon2.
Häh?
Achso, ich glaube, jetzt verstehe ich, was Du meinst. Man, den Text muss man aber drei mal lesen...
-
for_each(map.begin(), map.end(), boost::bind(&Base::foo, boost::bind(&std::map<std::string, Base*>::value_type::second, _1)));
-
camper schrieb:
for_each(map.begin(), map.end(), boost::bind(&Base::foo, boost::bind(&std::map<std::string, Base*>::value_type::second, _1)));
Find ich persönlich unintuitiv, schlecht lesbar und erstmal auch schwer verständlich.
-
Tachyon schrieb:
...Achso, ich glaube, jetzt verstehe ich, was Du meinst. Man, den Text muss man aber drei mal lesen...
Sorry, wenn Dir eine bessere Formulierung einfällt für
vector<myObj> v(10); myObj* o = &v[9]; v.resize(10000); o->doIt(); // Bumm !
bist Du herzlich eingeladen....
Gruß,
Simon2.
-
Tachyon schrieb:
camper schrieb:
for_each(map.begin(), map.end(), boost::bind(&Base::foo, boost::bind(&std::map<std::string, Base*>::value_type::second, _1)));
Find ich persönlich unintuitiv, schlecht lesbar und erstmal auch schwer verständlich.
Und da stimme ich zu, jedenfalls was die Lesbarkeit betrifft. Intuition ist so eine Sache, das hängt logischerweise auch immer von einer Vorkenntnis diesbezüglich (boost::bind&co.) ab. Ohne echte Lambda-Ausdrücke wird es leider nicht besser werden.
-
Ok ich bedanke mich für diese echt hilfreichen und auklärenden Antworten.
Wollte aber mal noch fragen, wann man polymorphismus denn normaler weiße verwendet oder wann man die methoden lieber über die "normalen" objekte anspricht. Kurz gesagt wann verwendet man Polymorphismus eher?
-
Firefighter schrieb:
Ok ich bedanke mich für diese echt hilfreichen und auklärenden Antworten.
Wollte aber mal noch fragen, wann man polymorphismus denn normaler weiße verwendet oder wann man die methoden lieber über die "normalen" objekte anspricht. Kurz gesagt wann verwendet man Polymorphismus eher?