nutzen von Funktionen einer geerbten Klasse in einer geerbten Klasse
-
Hallo zusammen,
ich habe ein kleines programmiertechnisches Problem vielleicht kann mir hier ja jemand helfen. Der Verständlichkeit halber werde ich das Problem schrittweise erklären:
Ich möchte eine Klasse bauen, die andere Klassen um bestimmte Funktionen erweitert, also nach dem Prinzip:
class X : newFunctions{}
class newFunctions{...}Die neuen Funktionen sollen aber auf bestimmte Funktionen in X zugreifen können
class X : newFunctions{ void foo();}
class newFunctions{
void xyz(){foo();}
}Die Funktionen von X sollen aber von einer anderen Klasse geerbt sein:
class X : Y, newFunctions{}
class Y{void foo();}
class newFunctions{
void xyz(){foo();}
}Leider darf die Klasse Y nicht verändert werden, sie ist also eine Blackbox.
Ich wollte das ganze mit Interfaces und virtuellen Funktionen machen:class X : Y, newFunctions{}
class Y{void foo();}
class newFunctions: IY{
void xyz(){foo();}
}
class IY{ virtual void foo()=0;}Leider klappte es nicht so, wie ich es mir vorgestellt habe. Hat jemand eine Idee wie ich richtig implementieren kann, oder geht diese Art der Logik einfach nicht in C++?
Schonmal vielen Dank für alle Antworten
Gruß
Bube
-
Bube schrieb:
Ich möchte eine Klasse bauen, die andere Klassen um bestimmte Funktionen erweitert, also nach dem Prinzip:
class X : newFunctions{}
class newFunctions{...}Also wenn ich dir richtig Folge soll "newFunctions" die erweiterung sein und "X" die Klasse die du erweiterst? Dann dreh bitte die Angaben um:
X ist die Basisklasse und newFunctions die Erweiterung:
class newFunctions : XSo, jetzt fehlt aber noch etwas entscheidendes. Könnte es sein das du aus dem Java-Umfeld kommst?
Das Ableiten wie man es in anderen Sprachen kennt, in denen keine Zugriffsangabe bei der Ableitung steht entspricht in C++ "public". Dies ist eine Besonderheit von C++ und in der Regel (es gibt ein paar Ausnahmen) sollte hier public stehen (Zumindest wenn du willst das die Funktionen der Basisklasse auch nach Außen sichtbar sein sollen).class newFunctions : public XJetzt kannst du auch in der Klasse "newFunctions" auf die Methoden der Basisklasse "X" zugreifen, sofern diese public oder protected deklariert wurden sind. Zudem sind alle Methoden und Attribute die in der Basisklasse public deklariert wurden nach außen sichtbar. newFunctions ist demzufolge eine Klasse die sich nach außen wie ein X verhält, aber um weitere Methoden/Funktionen ergänzt wurde.
Harken: Bei jeder Ableitung ist in der Regel der Destruktor der Basisklasse virtuel zu markieren. Wenn eine Klasse nicht geändert werden kann und keinen virtuellen Destruktor besitzt sollte man auf andere Sprachmittel als auf Ableitung zurückgreifen (Zumal eine Ableitung immer nur dann verwendet werden sollte wenn man wirklich sagen kann: <Abgeleitete Klasse> IST EIN <Basisklasse>; z.B. "Kreis" IST EIN(E) "Geometrische Figur").
Eine Alternative zur Ableitung ist es die "Basisklasse" als Element in die Neue zu übernehmen und über deren Schnittstelle nach außen hin zu Kapseln (Bedeutet aber auch das du jede Methode die von der Basisklasse sichtbar sein soll nochmal schreiben musst.
Also statt:
class Basisklasse { public: void foo(); ... } class NeueKlasse : public Basisklasse { public: // Hier steht indirekt alles aus der Basisklasse was in der Public // ist, sofern man es nicht überdeckt... // Also implizit steht hier z.B. "void foo()" ohne es selbst zu schreiben ... }class Basisklasse { public: void foo(); ... } class NeueKlasse { private: Basisklasse element; public: // Jetzt muss man aber alles übertragen was von der Basisklasse // sichtbar sein soll... void foo() { element.foo(); } ... }Letzteres nennt man auch Adapter (man kann einer Klasse X eine neue Schnittstelle verpassen indem man sie kapselt und über die Schnittstelle der Neuen Klasse anders aufrufbar macht).
Ein Vorteil gegenüber der Ableitung ist, das man beliebige Klassen als Basis nehmen kann, auch wenn diese nicht für die Ableitung bestimmt sind. Nachteil: man kann sie nicht über einen Pointer auf die Basisklasse ansprechen.
cu André
-
Hallo André,
danke für die schnelle Antwort.
Leider war die Erklärung nicht genau mein Problem. Ich habe zwar schonmal mit Java programmiert, aber habe mit C++ angefangen und arbeite auch weiterhin damit. Das mit dem public war Faulheit, hab nur Pseudocode hingeschrieben, sorry war halt schon spät. Hier noch mal der Code den ich eigentlich schreiben will:class Blackbox { public: Blackbox(){;} ~Blackbox(){;} void foo(){;} }; class Basisklasse { public: Basisklasse(){;} ~Basisklasse(); // virtual void foo()=0; // Klappt nicht void funktionNutztFoo() { // foo(); // die Funktion foo() aus blackbox soll genutzt werden. } }; class NeueKlasse : public Blackbox, public Basisklasse { public: NeueKlasse(){;} }; int main(int argc, char *argv[]) { NeueKlasse *x = new NeueKlasse; x->funktionNutztFoo(); return 1; }Der kommentierte Teil ist mein Problem. Ich möchte NeueKlasse erweitern mit Funktionen aus der Basisklasse, die aber auf Funktionen von Blackbox zugreifen sollen.
Blackbox stammt aus einer anderen Library (Qt) und darf nicht geändert werden.
Mit einem Adapter würde das ganze zwar funktionieren, hätte aber genau den Nachteil den ich eigentlich beseitigen wollte. Eine Menge zusätzlichen Schreibaufwand, da nicht nur eine Funktion genutzt werden soll sondern sehr viele. Ausserdem müsste diese Änderung für jede neue NeueKlasse gemacht werden.class Blackbox { public: Blackbox(){;} ~Blackbox(){;} void foo(){;} }; class Basisklasse { public: Basisklasse(){;} ~Basisklasse(); virtual void adapter()=0; void funktionNutztFoo() { adapter(); } }; class NeueKlasse : public Blackbox, public Basisklasse { public: NeueKlasse(){;} void adapter(){foo();} }; int main(int argc, char *argv[]) { NeueKlasse *x = new NeueKlasse; x->funktionNutztFoo(); return 1; }Anmerkung: Wenn Basisklasse von Blackbox erbt würde das ganze natürlich auch funktionieren, jedoch müsste ich dann für jede Blackbox eine neue Basisklasse schreiben in meinem Fall z.B. für (QWidget, QMainWindow, QGLWindow, ...)
-
class Blackbox { public: void foo(); }; class Basisklasse { public: virtual void nutzeBlackBox()=0; void machFachliches1(); void machFachliches2(); void fachFunktion() { machFachliches1(); nutzeBlackBox(); machFachliches2(); } }; class NeueKlasse : public Blackbox, public Basisklasse { public: void nutzeBlackBox() { foo(); } };Erst NeueKlasse kann Blackbox mit Basisklasse verknüpfen.
BTW:
- leere Konstruktoren und Destruktoren braucht keiner; kann/sollte man weglassen.
- Objekte braucht man nicht per new zu erzeugen, ein einfachesint main() { NeueKlasse x; x.fachFunktion(); return 0; }reicht vollkommen aus. In Deinem Code hast Du schon ein Speicherleck, was gerade (und nur) durch das (überflüssige) new entsteht.
Gruß,
Simon2.
-
Ok dass ist ja exakt mein 2. Beispiel, sprich ich werde also um einen Adapter nicht herumkommen.
Das mit dem new ist klar, aber soweit ich weiss, wird der Speicher nach Programmende ja freigegeben, so dass ich mich (wenn es in der main methode steht!) nicht weiter darum kümmern brauche.
Vielen Dank für die Antworten
-
Bube schrieb:
Ok dass ist ja exakt mein 2. Beispiel, ...
Hoppala ! Das hatte ich gar nicht gesehen (
shame-on-me
).Bube schrieb:
sprich ich werde also um einen Adapter nicht herumkommen.
Ich wüsste jedenfalls nicht, wie sonst die Verknüpfung der Klassen Basis und BlackBox zustande kommen sollte. Evtl. könnte man da mit templates was Fummeln (da werden eigentlich nur "Namen" aufgelöst und hat eine extrem lockere Kopplung), aber ich denke nicht, dass Dir das wirklich weiterhelfen würde (zumal Du ja offensichtlich Laufzeitpolymorphie brauchst).
Bube schrieb:
Das mit dem new ist klar, aber soweit ich weiss, wird der Speicher nach Programmende ja freigegeben, so dass ich mich (wenn es in der main methode steht!) nicht weiter darum kümmern brauche....
Nunja, man kann sich natürlich auf das Betriebssystem verlassen ... aber die Frage ist: Warum ?

Schließlich sind Stackvariablen sogar einfacher zu handhaben, schneller, ....Gruß,
Simon2.