Problem mit virtuellen Methoden
-
Hallo zusammen,
Ich hätte da auch mal ein Problem:
Hier erstmal die Aufgabenstellung die ich vorliegen habe:
______________________________________________________________________________
Gegeben ist folgender Quellcode:#include <iostream.h> class Insekt { protected: int laenge; int gewicht; public: Insekt (int, int); //Konstruktor Basisklasse virtual void Essen(); virtual void Ausgabe(); }; //Rumpf des Konstruktors Basisklasse Insekt::Insekt(int l, int g) { laenge = l; gewicht = g; } void Insekt::Essen() { laenge++; gewicht++; } void Insekt::Ausgabe() { cout << "Dieses Insekt ist " << laenge << " cm lang" << endl; cout << "und " << gewicht << "g schwer" << endl; }Aufgabe:
Leiten Sie aus der Basisklasse eine Klasse Libelle ab. Die Klasse Libelle soll
zusätzlich das Attribut fluegellaenge enthalten.Die Methode essen() der Klasse Libelle soll zusätzlich bewirken, dass die
Fluegellaenge um eins erhöht wird.Ändern Sie auch die Methode ausgabe() der Klasse Libelle so, dass zusätzlich
die Fluegellaenge ausgegeben wird.Erstellen Sie die Funktion main(), welche die Methoden in geeigneter Reihen-
folge und Häufigkeit aufruft. Das lauffähige Programm soll folgende Bildschirm-
ausgabe bewirken:Diese Libelle ist 20 cm lang
und 1g schwer
Sie hat eine Fluegellaenge von 20 cm
------------------------------------Diese Libelle ist 25 cm lang
und 6g schwer
Sie hat eine Fluegellaenge von 25 cm
------------------------------------Meine Lösung, die leider noch nicht funktionier, sieht so aus:
#include <iostream.h> class Insekt { protected: int laenge; int gewicht; public: Insekt (int, int); //Konstruktor Basisklasse virtual void Essen(int, int); virtual void Ausgabe(); }; class Libelle : public Insekt //Klasse Libelle abgeleitet von Insekt { private: int fluegellaenge; public: Libelle (int, int, int); //Konstruktor der abgeleiteten Klasse void Essen(int); void Ausgabe(); }; //Rumpf des Konstruktors Basisklasse Insekt::Insekt(int l, int g) { laenge = l; gewicht = g; } //Rumpf des Konstruktor der abgeleiteten Klasse: Libelle::Libelle(int l, int g, int f) : Insekt(l, g) { fluegellaenge = f; } void Libelle::Essen(int) { fluegellaenge++; } void Insekt::Essen(int, int) { laenge++; gewicht++; } void Libelle::Ausgabe() { cout << "Diese Libelle ist " << laenge << " cm lang" << endl; cout << "und " << gewicht << "g schwer" << endl; cout << "Sie hat eine Fluegellaenge von " << fluegellaenge << " cm" << endl; } void Insekt::Ausgabe() { cout << "Dieses Insekt ist " << laenge << " cm lang" << endl; cout << "und " << gewicht << "g schwer" << endl; } void main() { Insekt insekt(20,1); Libelle libelle(20,1,20); Insekt *Insektenliste[2]; Insektenliste[0]=&insekt; Insektenliste[1]=&libelle; Insektenliste[0]->Ausgabe(); cout << "\n"; Insektenliste[1]->Ausgabe(); cout << "--------------------------------------------------\n"; for (int i=0; i<5; i++) { Insektenliste[0]->Essen(20,1); Insektenliste[1]->Essen(20,1); } Insektenliste[0]->Ausgabe(); cout << "\n"; Insektenliste[1]->Ausgabe(); cout << "--------------------------------------------------\n\n"; char p[50]; cin.getline(p,50); }Und das ist meine Ausgabe:
Diese Libelle ist 20 cm lang
und 1g schwer
Sie hat eine Fluegellaenge von 20 cm
------------------------------------Diese Libelle ist 25 cm lang
und 6g schwer
Sie hat eine Fluegellaenge von 20 cm
------------------------------------Frage: Wo hängt's? Wo liegt mein Problem? Ich hab mittlerweile keine Ahnung mehr, wonach ich suchen soll. Und habe auch schon einige Bücher gewälzt... Ich finde das Problem nicht... Kann mir einer helfen, wieso mein Programm alle Stellen richtig ändert, bloß den letzten Wert (oben fett markiert) nicht???
Vielen Dank schon mal

-
Das liegt daran, dass Essen (int) nicht die gleiche Signatur hat wie Essen (int, int). Nur bei gleicher Signatur wird die Methode überschrieben. Was sollen diese Parameter überhaupt da?
P.S.: Es gibt weder <iostream.h> noch void main (). Bitte benutze <iostream>, std::cout und int main () stattdessen.
-
.filmor schrieb:
Das liegt daran, dass Essen (int) nicht die gleiche Signatur hat wie Essen (int, int). Nur bei gleicher Signatur wird die Methode überschrieben. Was sollen diese Parameter überhaupt da?
P.S.: Es gibt weder <iostream.h> noch void main (). Bitte benutze <iostream>, std::cout und int main () stattdessen.
Ich habe das gerade ausprobiert, beiden die gleiche Signatur zu geben. Dann wird aber nur noch der letzte Wert der Fluegellänge geändert und die beiden anderen nicht mehr.
Diese Libelle ist 20 cm lang
und 1g schwer
Sie hat eine Fluegellaenge von 20 cm
------------------------------------Diese Libelle ist 20 cm lang
und 1g schwer
Sie hat eine Fluegellaenge von 25 cm
-
Du musst dann auch dafür sorgen, dass die geerbte Methode aufgerufen wird:
void Libelle::Essen () { ++fluegellaenge; Insekt::Essen (); }
-
He... das war alles???? Das klappt!!! Du bist ja super!!! Vielen, vielen Dank!! Und ich dachte schon das wäre ein riesen Akt, was da nich stimmt... Ich war echt schon am verzweifeln!
DANKE!!!!!!!

-
Etwas "richtiger" wäre das ganze aber so:
#include <iostream> class Insekt { public: Insekt (int laenge, int gewicht) : _laenge (laenge), _gewicht (gewicht) {} virtual void Essen () { ++_laenge; ++_gewicht; } virtual void Ausgabe() { std::cout << "Dieses Insekt ist " << _laenge << " cm lang\n" "und " << _gewicht << "g schwer" << std::endl; } protected: unsigned int getLaenge () { return _laenge; } unsigned int getGewicht () { return _gewicht; } private: unsigned int _laenge; unsigned int _gewicht; }; class Libelle : public Insekt { public: Libelle(int laenge, int gewicht, int fluegellaenge) : Insekt(laenge, gewicht), _fluegellaenge (fluegellaenge) {} virtual void Essen () { ++_fluegellaenge; Insekt::Essen (); } virtual void Ausgabe () { std::cout << "Diese Libelle ist " << getLaenge() << " cm lang\n" "und " << getGewicht() << " g schwer\n" "Sie hat eine Fluegellaenge von " << _fluegellaenge << " cm" << std::endl; } private: unsigned int _fluegellaenge; }; int main() { Insekt insekt(20,1); Libelle libelle(20,1,20); Insekt* Insekten[2]; Insekten[0]=&insekt; Insekten[1]=&libelle; Insekten[0]->Ausgabe(); std::cout << "\n"; Insekten[1]->Ausgabe(); std::cout << "--------------------------------------------------\n"; for (int i=0; i<5; i++) { Insekten[0]->Essen(); Insekten[1]->Essen(); } Insekten[0]->Ausgabe(); std::cout << "\n"; Insekten[1]->Ausgabe(); cout << "--------------------------------------------------\n\n"; cin.get (); }
-
aber die methoden der unterklasse müssen doch nur dann virtual sein, wenn man von der unterklasse nochmal vererben will und dort die methode wieder "überschreiben" will, oder?
-
Nein. Wenn in einer abgeleiteten Klasse in der Deklaration einer bereits geerbten virtuellen Methode virtual steht, bewirkt das gar nichts. Geerbte virtuelle Methoden bleiben virtuell. Auch weiter abgeleitete Klassen können sie neu definieren. Es ist halt nur übersichtlicher, wenn man weiß, welche Methoden virtuell sind und welche nicht.
-
.filmor schrieb:
Etwas "richtiger" wäre das ganze aber so:
Danke, das ist nett. Das drucke ich mir auf jedenfall mal aus, zum späteren Nachsehen... Übernehmen kann ich es 1:1 nicht, da ich den vorgegebenen Code nur bedingt abändern durfte... Trotzdem danke nochmal.
-
@filmor:
Ich dachte Bezeichner mit Underscore vorneweg seien der Implementierung vorbehalten?
-
AFAIK gilt das innerhalb der Klasse nur für __ (doppelten Unterstrich). Im globalen Namensraum hast du Recht.
-
doppelter unterstrich (irgendwo im namen) und beginnender unterstrich mit foplgendem großbuchstaben sind für jeden zweck reserviert (insbesondere eben z.b. macros). andere bezeichner mit unterstrich am anfang sind nur für bezeichner im globalen namensraum reserviert.