Problem bei Polymorphie
-
Hallo,
ich hab ein Problem mit der Verarbeitung von Elementen. Insgesamt habe ich 8 Elemente. Pro Element eine Klasse. Um die Elemente einfach zu verwalten habe ich den Elementen eine Basisklasse gegeben und halte sie so in einem vector zusammen.
vector<basis> elemente;Nun habe ich das Problem, dass manche Elemente untereinander Abhängigkeiten haben. Die Abhängigkeit wird in Form der ID des Vektors gespeichert.
Für jeden Typ im Vektor habe ich eine Funktion, die das Element verarbeiten kann, da alle Elemente verarbeiten werden müssen, dass aber auf eine unterschiedeliche Art und Weise.
Somit habe ich ein paar Prototypen:bool bearbeite( vector<basis>&, foo&, size_t ); bool bearbeite( vector<basus>&, bar&, size_t ); bool bearbeite( vector<basus>&, baz&, size_t );//Aufruf der Funktion bearbeite( elemente, elemente[5] ); // [...] /* Im Vektor "elems" sind jetzt verschiedene Elemente gespeichert. Relevant ist, das darin Elemente vom Typ "foo" und "bar" sind. Die Funktion braucht alle Elemente aus dem Vektor, die vom Typ "bar" sind. */ bool bearbeite( vector<basis> &elems, //Alle Elemente foo &diesesElement, //Das zu verarbeitende Element size_t elemId ) //Die ID des zu verarbeitenden Elementes im übergebenen Vektor { //Alle Elemente des Types "bar" per Index selektieren vector<size_t> bar_elems; }Ich habe gelesen, dass es da irgendetwas mit typeid und so gibt. Aber in der Richtung kenne ich mich (noch) nicht aus.
Kann mir jemand helfen, die Elemente zu selektieren? Ich hoffe, ich habe mein Problem verständlich erklärt
Danke schon mal!
MfG. Ich
-
Erstmal die Lösung: Gib den abgeleiteten Klassen jeweils eine Methode in der drin steht, wie sie zu verarbeiten sind. Deine Funktion ruft dann diese Methode auf und es wird automatisch die passende gewählt, das ist ja gerade der Sinn an der Polymorphie.
Und noch eine Anmerkung: Dir ist doch hoffentlich klar, dass du Polymorphie über Basisklassenzeiger und nicht über Basisklassenelemente machen musst?
-
Hallo,
du meinst also, ich muss...
vector<basis*> elemente //...verwenden, anstatt... vector<basis> elemente //?Ich hab noch ein Problem. Meine Funktionen sehen ja so aus:
bool bearbeite( vector<basis> &elems, foo &elem, size_t elemId ); bool bearbeite( vector<basis> &elems, bar &elem, size_t elemId ); bool bearbeite( vector<basis> &elems, baz &elem, size_t elemId ); //...Wenn ich nun die Funktion aufrufe, mache ich das so:
vector<basis> elemente; //elemente füllen... bearbeite( elemente, elemente[5], 5 );Hier gibt der Kompiler mir den Fehler, dass er nach
bool bearbeite( vector<basis> &elems, basis &elem, size_t elemId );sucht. Wie muss ich das umschreiben, damit er die mit foo überladene Funktion aufruft?
MfG. Ich
-
du musst die bearbeiten methode in die klassen einfuegen die von der basisklasse erben. Jede Klasse weiß ja wie eine Instanz zu bearbeiten ist. Du definierst alsoin der Basusklasse eine virtuelle funktion
virtual void bearbeiten()Diese weren nun in den Klassen die erben ueberschrieben mit dem passenden Algorithmus.
Du speicherst nun in einem vector die Instanzen als Zeiger auf die Basisklasse
vector<Basis*> v;Beim einfuellen musst du dem Zeiger eine Instanz der abgeleiteten Klasse zuteilen, wenn du nun beim bearbeiten
v[index].bearbeiten()aufrufst wird sofort der richtige Algorithmus ausgeführt.
um mehrere eintraege zu bearbeiten schreibst du dir dann nonch eine globale Funktion, die per schleife die Elements durchnimmt und jeweils die funktion bearbeiten() der einzelnen instamzen aufruft.
-
Hmm gut, so hab ich das jetzt umgesetzt.
In einer Klasse habe ich eine Funktion. Diese Klasse erbt von der Basisklasse und ist in dem Vektor gespeichert.class Basis { }; class Erbe : public Basis { public: int foo(); }; int main() { vector<Basis*> elemente; //.... elemente[5]->foo(); //... }Der Aufruf von foo() scheitert, da der Compiler in der Methodenliste von Basis sucht. So meckert der Compiler nicht mehr:
static_cast<Erbe*>( elemente[5] )->foo();Aber diese Lösung scheint mit eher absurd. Muss ich foo in der Basisklasse erst noch virtuell deklarieren oder wie sollte ich das machen?
MfG. Ich
-
Muss ich foo in der Basisklasse erst noch virtuell deklarieren oder wie sollte ich das machen?
Genau so.
-
Da ist dann aber das Problem, dass eine andere Klasse diese virtuelle Klasse erbt, aber nicht implementiert, aber trotzdem aufgerufen werden kann, also so:
class Basis { virtual bool foo(); }; class bar : public Basis { bool foo(); }; bool bar::foo() //Implementierung ist eigentlich in einer anderen Datei { //... } class baz : public Basis {}; int main() { vector<Basis*> elemente( 2 ); elemente[0] = new bar(); elemente[1] = new baz(); //... elemente[1]->foo(); return 0; }Sieht der Kompiler sowas oder gibts da (Laufzeit-)Fehler?
Baz, hat ja foo() als Prototypen, aber implementiert diese Funktion nicht.
Sorry, aber an dem Rechner kann ich das grad nicht ausprobieren...MfG. Ich
-
Dann ist dein Design falsch. Denn wenn baz ein Basis ist und der Algorithus auf Basis-Objekte wirkt, dann muss es logischerweise auch einen Algorithmus für baz geben.
-
Nein. Baz ist keine Basis Es geht um einen Getter:
class Basis { virtual size_t getBlubb(); }; class bar : public Basis { private: size_t blubb; public: size_t getBlubb(); }; size_t bar::getBlubb() { return this->blubb; } class baz : public Basis {}; int main() { vector<Basis*> elemente( 2 ); elemente[0] = new bar(); elemente[1] = new baz(); //... elemente[1]->getBlubb(); //baz hat getBlubb() nicht definiert return 0; }Basis ist das "Elternelement". Von diesem erben bar und baz. Aber bar definiert die Funktion getBlubb(). Die anderen, von Basis erbenden, Klassen nicht.
-
Wie gesagt, dein Design ist falsch. Die public Vererbung
class baz : public Basisdrückt aus, dass baz ein Basis ist. Und daher muss es dann auch mindestens alles haben, was ein Basis auszeichnet. Hat es das nicht, dann ist baz kein Basis und dein Design ist falsch.
-
1. -> abstrakte Basisklasse...
wenn du in der Basisklasse angibst
class Basis { virtual bool foo() = 0; };gibt es keine Implementierung in der Basisklasse und deine erbenden klassen werden aufgefordert eine Implementierung darzubieten. so lange sie dies nicht tun bleiben sie auch abstrakt und es kann keine instanz gebildet werden
2. Es gibt keinen sinn getSize_t() in der Basisklasse zu deklarieren und dann in jeder klasse size_t als Element zu definieren. Alles was die klassen gemeinsam haben muss in die Basisklasse. Du kannst auch auf diese Elemente so lange sie protected sind frei zugreifen in der abgeleiteten klasse
-
Hallo,
zu 1.:
Also mache ich in den erbenden Klassen, die die Funktion nicht benötigen, einen "sinnlosen" Rückgabewert.> erledigt.
zu 2.:
Es ging um ein Attribut, welches nur eine Erbende Klasse hat. Dieses Attribut wird aber zur Verarbeitung in einer Methode einer anderen Klasse gebraucht. In etwa so:enum ELEMENT_TYP { ET_FOO ET_BAR }; class Basis { private: ELEMENT_TYP typ; public: virtual void bearbeite( vector<Basis*> &elems ); virtual size_t getAttribut() = 0; bool setTyp( ELEMENT_TYP newTyp ) { //... this->typ = newTyp; return true; } ELEMENT_TYP getTyp() { return this->typ; } }; class foo : public Basis { private: size_t attribut; public: foo() { this->setTyp( ET_FOO ); } size_t getAttribut() { return this->attribut; } void bearbeite( vector<Basis*> &elems ) { //... } }; class bar : public Basis { public: bar() { this->setTyp( ET_BAR ); } void bearbeite( vector<Basis*> &elems ) { size_t elemsSize = elems.size(); for( size_t i = 0; i < elemsSize; ++i ) { if( elems[i]->getTyp() == ET_FOO ) { //Ich habe nur den Vektor, brauche daraus aber foo::attribut this->machIrgendwas( elems[i]->getAttribut() ); } } } };Es geht um dieses eine Attribut und um diesen einen Getter. Die beiden Member sind _nur_ in foo vorhanden. Ich muss das Attribut aber in anderen Klassen( z.b. bar ) benutzen, weswegen ich eine Methode brauchte, um aus dem Element-Vektor das Attribut zu bekommen. Deswegen muss ich getAttribut schon in Basis bekannt machen.
MfG. Ich
-
1. hmm ich glaube du hast meinen Vorschlag im erster Post nicht richtig verstanden...
du sollst nicht in jeder einzelnen klasse den ganzen vektor vergleichen, ich meinte dass du überhaupt nicht vergleichen sollst in den abgeleiteten klassen sondern den vorteil der polymorphie nutzen sollst.2. Nein wenn nicht alle Klassen eine Funktion benötigen, gehört diese Funktion nicht in die unterste Basisklasse, das wäre ein Designfehler!
Du verrenst dich da gerade in unnötige Probleme, da du wahrscheinlich nicht richtig weißt wie du die Polymorphie nutzen kannst.
Außerdem wird dein Code nicht funktionieren, da die Funktion bearbeiten nur aufgerufen wird wenn du eine instanz die im vector gespeichert ist aufrufst.
Ich würde die anraten Vererbung und Polymorphie dir anzusehen, da du sonst nicht den folgenden Code verstehen wirst. Ich habe dir hier mal einen funktionieren code beschrieben mit der Grundstruktur.
#include <iostream> #include <vector> using namespace std; class Basis { public: virtual void bearbeite() = 0; virtual ~Basis(){} }; class Abg1 :public Basis { public: virtual void bearbeite() { cout << "Bearbeite gerade eine Instanz der Klasse Abg1" << endl; } }; class Abg2: public Basis { public: virtual void bearbeite() { cout << "Bearbeite gerade eine Instanz der Klasse Abg2" << endl; } }; class Abg3: public Basis { public: virtual void bearbeite() { cout << "Bearbeite gerade eine Instanz der Klasse Abg3" << endl; } }; class Abg4: public Basis { public: virtual void bearbeite() { cout << "Bearbeite gerade eine Instanz der Klasse Abg4" << endl; } }; void bearbeite_elemente(const vector<Basis*> &v, unsigned int begin, unsigned int end) { if(begin < v.size() && end < v.size()) { for(unsigned int counter = begin; counter <= end; counter++) v[counter]->bearbeite(); } else { cout << "Paramter out of range!" << endl; } } int main() { //hier wird dein Vector mit dem Zeiger auf die Basis definiert vector<Basis*> v(10); //einfüllen der elemente v[0] = new Abg1(); v[1] = new Abg4(); v[2] = new Abg2(); v[3] = new Abg3(); v[4] = new Abg4(); v[5] = new Abg2(); v[6] = new Abg2(); v[7] = new Abg1(); v[8] = new Abg3(); v[9] = new Abg1(); //Bearbeiten der elemente bearbeite_elemente(v,1,5); cin.get(); }Teste es aus und du wirst sehen, dass deine Klasse nicht zu wissen braucht welcher Typ sie hat, dadurch dass du bearbeite() auf einen Zeiger der Basisklasse aufrufst wird automatisch die Funktion der richtigen erbenden klasse aufgerufen. Es wird die Funktion der Klasse die du dem Zeiger vorher zugeteilt hast aufgerufen
-
Schön und gut, dass was du da geschrieben hast, nur das weis ich schon. Ich weis, was Vererbung und Polymorphie ist. Du hast mein Problem( was im übrigen jetzt nicht mehr existiert ) nicht verstanden. Aber egal, Es ist nur eine Übung gewesen und die nächste Übung wird besser.
Ach ja... dass das Design-technisch nicht ganz ok ist, dem bin ich mir bewusst.Aus Zeitmangel werde ich an der Sache jetzt aber nichts mehr ändern.
Danke trotzdem für eure Hilfe!Frohes neues!
MfG. Ich