Verständnissproblem bei Polymorphismus!
-
Hallo Forenmitgliedern!
Ich bin gerade dabei, die Vererbung von C++ zu lernen, bleibe bei einem praktischen Beispiel aber leider total hängen.
Meine Idee welche ich umsetzen möchte ist folgende:
Es gibt mehrere Items, welche alle eine ID und einen Preis haben und sich in ihrer Funktion und in ihrem Output unterscheiden.
Deswegen möchte ich eine Basisklasse Items machen und davon dann konkrete Items(z.B. Potions) ableiten.
Meine Basisklasse (Items.h):class Items { public: int id_; int price_; void output(); void execute(); };So, nun habe ich eine abgeleitete Klasse Potion:
class Potion : public Items { public: int getAmount(); };Diese hat jetzt die Membervariablen id_ und price_.
Hier ist jetzt mein Verständnissproblem.
Wenn ich die konkreten Werte von id_ und price_ jetzt im Konstruktor initialisiere mit:Potion::Potion() { price_ = 200; id_ = 0; }habe ich dann eine Speicherersparnis?
Also habe ich den konkreten Wert 200 von price_ dann auf die Speicherstelle von price_ der Basisklasse geschrieben, oder wird ein eigener Speicher dafür initialisiert?
Was habe ich hier jetzt für einen Vorteil gegenüber wenn ich für jedes Item price_ und id_ extra initialisiere (außer Codelänge).Wenn ich in der main.cpp mit
Potion potion;ein Objekt instantiieren möchte, dann kommt der Fehler undefined reference to `Potion::Potion()
Ich habe die Header aber includiert!
Danke schon im Vorhinein für die Antworten!
mfg trunksen
-
Also erst mal hat undefined Reference im Normalfall nichts mit den Headern zu tun, sondern mit der Definition, diese steht ja normal in einer Quelldatei.
So dann, hast du im Konstruktor von Potion keine Initialisierungen, sondern Zuweisungen. Man nimmt dafür normalerweise die Elementinitialisierungsliste:
Potion() : price_2( 200 ), id_( 0 ) {}Zudem, musst aber der Konstuktor der Basisklasse, den Basisteil initialisieren.
Du musst ihn also in der Elementinitialisierungsliste aufrufen:Potion() : Items() {}Dieses Beispiel ergibt aber keinen Sinn, hier würde es reichen den Basiskonstruktor zu definieren, und bei der abgeleiteten Klasse den Standardkonstruktor vom Compiler zu verwenden, da er automatisch den Basiskonstruktor aufruft und deine abgeleitete Klasse ja keine neuen Elemente hat.
Lg freeG
-
Meine Basisklasse (Items.h):
class Items { public: int id_; int price_; void output(); void execute(); };Die Member id und price sollten private sein, höchsten protected, aber nicht public. Sonst kann da jeder dran rumpfuschen. Das widerspricht dem Konzept der Kapselung.
trunksen schrieb:
So, nun habe ich eine abgeleitete Klasse Potion:
class Potion : public Items { public: int getAmount(); };Diese hat jetzt die Membervariablen id_ und price_.
Nein, nicht direkt. Sie hat ein Basisklassenobjekt vom Typ Items, und das hat die beiden Membervariablen.
trunksen schrieb:
Wenn ich die konkreten Werte von id_ und price_ jetzt im Konstruktor initialisiere mit:
Potion::Potion() { price_ = 200; id_ = 0; }habe ich dann eine Speicherersparnis?
Du solltest die Werte durch den Konstruktor der Basisklasse initialisieren, nicht im eigentlichen Konstruktor. Lies dir mal im Netz ein paar Dinge zum Thema "Vererbung" und "Ist-ein"-Beziehung durch.
Also habe ich den konkreten Wert 200 von price_ dann auf die Speicherstelle von price_ der Basisklasse geschrieben, oder wird ein eigener Speicher dafür initialisiert?
Richtig, du änderst direkt die Member der Basisklasse. Ist aber schlechter Stil, wie gesagt, Kapselung und so

Was habe ich hier jetzt für einen Vorteil gegenüber wenn ich für jedes Item price_ und id_ extra initialisiere (außer Codelänge).
Es geht nicht nur um Codelänge, sondern auch um Wiederverwendung von Code - und darum dass du eine Änderung am gemeinsamen Verhalten von items nicht per Copy&Paste an jeder einzelnen Klasse vornehmen musst (und am Ende ein oder zwei übersiehst). Es gibt noch weitere wichtige Gründe für Vererbung, z.B. Polymorphie, allerdings geht das schon über deine Kenntnisse hinaus, da fehlen scheinbar noch die Basics, und die solltest du zuerst sicher und verstanden haben.
Wenn ich in der main.cpp mit
Potion potion;ein Objekt instantiieren möchte, dann kommt der Fehler undefined reference to `Potion::Potion()
Ich habe die Header aber includiert!
Danke schon im Vorhinein für die Antworten!
mfg trunksen
Hast du den Kontruktor im Header definiert? Falls nein, musst du auch die .cpp wo du ihn definiert hast mit zu deinem Projekt linken.
Falls ja, zeig uns bitte den genauen Code (Klassendefinition und Aufruf des Konstruktors)
-
Vielen Dank für die schnellen Antworten!
Dieses Beispiel ergibt aber keinen Sinn[...]
Wie gesagt, ich habe da noch ein Verständnissproblem!
Du solltest die Werte durch den Konstruktor der Basisklasse initialisieren
Ok, das verstehe ich jetzt nicht! Dann habe ich ja einen Wert für price_ und id_ für alle Items! Oder wie werden die dann zugewiesen?
Also ich habe einmal probiert den Basiskonstruktor so zu schreiben:Items::Items(int price_, int id_) { }und keinen Potion Konstruktor mehr.
Wenn ich jetztPotion potionmache, wird dann dieser Konstruktor aufgerufen?
Und wie weiße ich jetzt die konkreten Werte für Potion id_ zu?Lies dir mal im Netz ein paar Dinge zum Thema "Vererbung" und "Ist-ein"-Beziehung durch.
Habe ich, allerdings habe ich noch kein gutes praktisches Bsp. gefunden, sondern immer nur Theorie (a la: protected Ableiten etc.)
mfg trunksen
-
Du mußt dem Compiler mitteilen, welchen Konstruktor er verwenden soll (andernfalls nimmt er den Default-Konstruktor, sofern einer existiert):
class Potion : public Items { public: Potion() : Items(200,0) {} //Aufruf des Basis-Ctors ... };
-
Hallo!
Wieder danke für die Antwort und eine Entschuldigung, dass ich so spät erst wieder antworte!
Ich habe jetzt die Methode von CStoll probiert und ein neues Item (Monsterball) hinzugefügt!
Basisklasse Items.h:class Items { protected: int id_; int price_; Items(int id_, int price_); public: void output(); void execute(); };Potion.h:
class Potion : public Items { public: int getAmount(); Potion(): Items(200,0) {} };MonsterBall.h:
class Monsterball : public Items { public: Monsterball(): Items(300,1) {} };und zu am Schluss die main.cpp

#include <iostream> #include "Items.h" #include "Potion.h" #include "MonsterBall.h" int main() { Potion potion; Monsterball mb; }Hier kommt jetzt aber ein undefined reference Fehler:
/tmp/ccQyNoqo.o: In function `Potion::Potion()': main.cpp:(.text._ZN6PotionC2Ev[_ZN6PotionC5Ev]+0x1d): undefined reference to `Items::Items(int, int)' /tmp/ccQyNoqo.o: In function `Monsterball::Monsterball()': main.cpp:(.text._ZN11MonsterballC2Ev[_ZN11MonsterballC5Ev]+0x1d): undefined reference to `Items::Items(int, int)' collect2: ld returned 1 exit statusWenn ich die Fehlermeldung richtig interpretiere, dann hat er beim Aufruf der Konstruktoren in der main keinen Link zum Ctor von Items.
Aber warum, ich habe Items.h ja includiert.Hoffe jemand kann mir helfen.
mfg trunksen
-
Es gibt dort aber keine Definition für den Items Konstruktur, nur eine Deklaration.
-
trunksen schrieb:
Wenn ich die Fehlermeldung richtig interpretiere, dann hat er beim Aufruf der Konstruktoren in der main keinen Link zum Ctor von Items.
Aber warum, ich habe Items.h ja includiert.Es fehlt "ihm" nicht der Link... Dem Linker fehlt die Defintion (sprich: Implementierung) des Konstruktors. Diese hast du wahrscheinlich in einer .cpp liegen. Diese muss erst kompiliert und das entstehende object-file mitgelinkt werden.
Wie kompilierst du denn?
-
Diese muss erst kompiliert und das entstehende object-file mitgelinkt werden.
*Gegenkopfhau* Ja klar!
Ich habe jetzt eine Items.cpp erstellt mit:#include <iostream> #include "Items.h" Items::Items(int id_, int price_) { }und diese mit -Wall mit-compiliert.
Jetzt funktioniert es!Vielen vielen dank für eure Hilfe!
mfg trunksen