Vererbung, aber wie richtig?
-
Hallo zusammen.
Ich brauche Hilfe zu folgendem Problem. Ich habe zwei Klassen, wobei eine davon ein Memberobjekt der anderen ist, also sowas wie
class Motor { protected: int Drehzahl; public: Motor() {Drehzahl = 5000;}; int GetDrehzahl() {return Drehzahl;} }; class Auto { protected: Motor myMotor; int anzahl_raeder; public: Auto() {anzahl_raeder = 4;}; void PrintInfo() {cout << myMotor.GetDrehzahl() << "\t" << anzahl_raeder << endl;} };
So weit, so gut. Nun sollen die Klassen aber erweitert werden, und hier faengt mein Problem an. Wenn nur die Klasse "Auto" etwas neues bekommen sollte, kann man ja relativ einfach etwas vererben. Die Klasse "Motor" soll aber auch z.B. neue Membervariablen erhalten. Das sieht dann z.B. so aus:
//Vererbung von Memberobjekt class Elektromotor : public Motor { private: int Stromverbrauch; public: Elektromotor() {Stromverbrauch = 42; Drehzahl = 6000;} int GetStromverbrauch() {return Stromverbrauch;}; };
Was mach ich jetzt aber mit "Auto", das zusaetlich zu eigenen Erweiterungen auch einen "Elektromotor" bekommen soll?
Hier mal meine eigenen Loesungsansaetze:
Eine einfach Loesung waere so etwas wie
/* Vererbung Version 1 */ class Elektroauto : public Auto { private: Elektromotor myMotor; char kennzeichen; public: Elektroauto() {kennzeichen = 'A';}; void PrintInfo_richtig() {cout << myMotor.GetDrehzahl() << "\t" << anzahl_raeder << endl;} void PrintInfo2() {cout << myMotor.GetStromverbrauch() << "\t" << kennzeichen << endl;} };
Das Problem hierbei ist, das ja der "alte Motor" immer noch vorhanden ist, wie man relativ leicht feststellen kann
Elektroauto myAuto1; myAuto1.PrintInfo(); //Ausgabe: 5000 4 (alter Motor) myAuto1.PrintInfo_richtig(); //Ausgabe: 6000 4 myAuto1.PrintInfo2(); //Ausgabe: 42 A
ich koennte bei der Vererbung natuerlich PrintInfo() ueberschreiben und alles waere gut, aber...
...das kommt mir unsauber vor
...in der Realitaet haette ich ziemlich viel zu ueberschreiben
...moechte ich keine unnoetigen Daten herumschleppen
Kurz gesagt ich will den Motor aus der Elternklasse nicht mehr.Eine andere Moeglichkeit sehe ich in Templates, also soetwas zu machen wie
/* Vererbung Version 2 (mit templates) */ template <typename T> class Auto2 { protected: T myMotor; int anzahl_raeder; public: Auto2() {anzahl_raeder = 4;}; void PrintInfo() {cout << myMotor.GetDrehzahl() << "\t" << anzahl_raeder << endl;} }; template <typename T> class Elektroauto2 : public Auto2<T> { private: char kennzeichen; public: Elektroauto2() {kennzeichen = 'A';}; void PrintInfo2() {cout << Auto2<T>::myMotor.GetStromverbrauch() << "\t" << kennzeichen << endl;} //Nerviges voranstellen von "Auto2<T>::" };
Hier sehe ich das Problem darin, dass das relativ kompliziert ist, da ich imho fuer alle Variablen und Funktionen dieses "Auto2<T>::" vorausstellen muss, die ich innerhalb der Klasse aufrufe (richtig?) da ich sonst von meinem Compiler (g++) angemeckert werde. Der Vollstaendigkeit halber mal die Fehlermeldungen die dann entstehen:
Bei Variablen:'XYZ' was not declared in this scope
Bei Methoden:
there are no arguments to 'XYZ' that depend on a template parameter, so a declaration of 'XYZ' must be available (if you use '-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated)
Wenn ich per -fpermissive kompiliere funktioniert es tatsaechlich, allerdings ist mir das irgendwie nicht geheuer. Abgesehen davon wuerde das mit den Templates etwas unhandlich in meinem realen Programm, schon allein weil man Definitionen und Deklarationen in die selbe Datei schreiben muss.
Ich hoffe deshalb einfach mal, auch weil mir das irgendwie wie ein Standardproblem vorkommt, das jemand eine praktikablere Loesung hat.
Viele Gruesse, n0x
-
Ich finde das Beispiel "Auto mit Motor" zu künstlich. Es ist nicht klar, was Du überhaupt erreichen willst.
Hast Du ein konkreteres Design-Problem?
-
class IMotor { private: size_t drehzahl; public: IMotor(size_t drehzahl_) : drehzahl(drehzahl_) { } size_t getDrehzahl() const { return drehzahl; } virtual void printMotorInfo() { std::cout << "Drehzahl: " << getDrehzahl() << std::endl; } }; class Ottomotor : public IMotor { public: Ottomotor() : IMotor(5000) { } }; class Elektromotor : public IMotor { private: size_t stromverbrauch; public: Elektromotor() : IMotor(6000), stromverbrauch(42) { } size_t getStromverbrauch() const { return stromverbrauch; } virtual void printMotorInfo() { IMotor::printMotorInfo(); std::cout << "Stromverbrauch: " << stromverbrauch << std::endl; } };
-
@krümel: ja, ich merke grad auch das anscheinend nicht klar ist was ich meine.
@kjjlkl: danke für die mühe, aber das meinte ich leider nichtich versuch es mal anders zu formulieren, in kurzform:
Es gibt eine Klasse A, diese enthält ein Memberobjekt von einer Klasse B.
Jetzt wird eine neue Klasse B2 definiert, die von Klasse B erbt.
Was ich möchte ist jetzt eine Klasse A2, die von A erbt, allerdings soll in A2 nicht B sondern B2 verwendet werden. Also Klasse A enthält B, Klasse A2 enthält B2.Im (ganz) obigen Beispiel entspricht A dem Auto, B dem Motor, B2 dem Elektromotor und A2 dem Elektroauto.
Ich hoffe es ist jetzt klarer was ich meine, sonst lass ich mir noch ein anderes Beispiel einfallen.
-
n0xinger schrieb:
Was ich möchte ist jetzt eine Klasse A2, die von A erbt
Warum soll A2 von A erben?
-
du könntest das per pointer lösen (=> smart pointer)
und dann halt eine nue instanz deines derivats erzeugenclass A { }; class A2 : public A { } class B { boost::shared_pointer<A> ptr; public: B() : ptr(new A) { } }; class B2 : public A { B2() : ptr(new A2) { } };
-
krümelkacker schrieb:
n0xinger schrieb:
Was ich möchte ist jetzt eine Klasse A2, die von A erbt
Warum soll A2 von A erben?
Sehe ich genauso, ein Auto ist ein Auto ein Elektroauto hat einfach nur andere Komponenten (elektromotor etc.)