Interfaces und Implementierung
-
Hallo, folgendes Problem:
#include <iostream> class A { public: void virtual func() = 0; }; class B : public A { public: void virtual func() {std::cout << "furz" << std::endl;} }; class C : public A { }; class D : public B, public C { }; int main() { D d; d.func(); return 0; }Funktioniert, allerdings mit einem Warning ("Warnung 1 warning C4250: 'D': Erbt 'B::B::func' via Dominanz"):
#include <iostream> class A { public: void virtual func() = 0; }; class B : public virtual A { public: void virtual func() {std::cout << "furz" << std::endl;} }; class C : public virtual A { }; class D : public B, public C { }; int main() { D d; d.func(); return 0; }Wie bekomme ich das Warning weg?
(ich habe das Beispiel in diesem Beitrag zur besseren Darstellung des Fehler ausgetauscht)
-
Wenn ich nun von SMyUnitName eine Instanz erstellen will, sagt mir der Compiler, dass keine Instanz von eine abstrakten Klasse erstellt werden kann. Ich hab herraus gefunden, dass dieser Fehler kommt, da er eine Implementation von "virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override;" vermisst (diese Funktion wird in sf::Drawable deklariert).
Unwahrscheinlich. Der Fehler kommt eher daher, dass du refresh als rein virtuell deklariert und in der abgeleiteten Klasse nicht überschrieben hast -- jedenfalls nicht mit derselben Signatur. Einmal ist es const, einmal nicht, das sind deutlich verschiedene Typen.
-
peinlicher Fehler
-
Wenn du von einer Basisklasse erbst, muss diese zum Zeitpunkt des Erbens vollständig definiert sein. Ordne die Klassendefinitionen entsprechend.
Und minimiere den Code, dass nur noch das absolut Notwendige da ist, um den Fehler zu erzeugen.
-
Nexus schrieb:
Wenn du von einer Basisklasse erbst, muss diese zum Zeitpunkt des Erbens vollständig definiert sein. Ordne die Klassendefinitionen entsprechend.
Das stimmt doch überhaupt nicht: Wenn nicht alle Funktionen von der Basisklasse implementiert werden, wird die Kindklasse automatisch zu einer abstrakten Klasse.
Mein Problem liegt darin, dass draw offensichtlich 2 mal in der VTable auftaucht, weil ich 2 mal von sf::Drawable erbe. Wenn ich das Schlüsselwort virtual (class A : virtual
dazu schreibe, kann ich compilieren, allerdings bekomme ich dann ein Warning, dass die Methode draw beim Vererben durch dominanz erzwungen wurde.Hier nochmal genau mein Problem:
Funktioniert nicht ("error: Instanz von abstrakter Klasse kann nicht erstellt werden"):#include <iostream> class A { public: void virtual func() = 0; }; class B : public A { public: void virtual func() {std::cout << "furz" << std::endl;} }; class C : public A { }; class D : public B, public C { }; int main() { D d; d.func(); return 0; }Funktioniert, allerdings mit einem Warning ("Warnung 1 warning C4250: 'D': Erbt 'B::B::func' via Dominanz"):
#include <iostream> class A { public: void virtual func() = 0; }; class B : public virtual A { public: void virtual func() {std::cout << "furz" << std::endl;} }; class C : public virtual A { }; class D : public B, public C { }; int main() { D d; d.func(); return 0; }Nur will ich dieses Warning halt weg bekommen.
-
Mr.Long schrieb:
Das stimmt doch überhaupt nicht: Wenn nicht alle Funktionen von der Basisklasse implementiert werden, wird die Kindklasse automatisch zu einer abstrakten Klasse.
Das hat nichts mit abstrakt/nicht abstrakt zu tun. Es geht nur um die Reihenfolge der Klassendefinitionen.
Mr.Long schrieb:
Wenn ich das Schlüsselwort virtual (class A : virtual
dazu schreibe, kann ich compilieren, allerdings bekomme ich dann ein Warning, dass die Methode draw beim Vererben durch dominanz erzwungen wurde.Du willst keine virtuelle Vererbung, finde stattdessen ein ordentliches Design.
Ohnehin gibts in C++ meist bessere Ansätze als tiefe Vererbung. Warum hast du den Diamond of Death und kannst nicht Komposition (Member statt Basisklasse) einsetzen?
-
Das ist so:
class ISurface : public virtual sf::Drawable { public: virtual void refresh(const Game::IGame& field) = 0; }; class ISUnit : public virtual ISurface { }; class SUnitImpl : public SurfaceImpl, public ISUnit { public: virtual void refresh(const Tactics::Game::IGame& game); }; class SUnitFurgon : public SUnitImpl { public: }; class SField : public SurfaceImpl { public: virtual void refresh(const Tactics::Game::IGame& game); };SUnitFurgon ist ein Objekt, welches gezeichnet werden soll, daher ich mehrere Units habe will ich die Units durch SUnitImpl verallgemeinern. ISUnit soll, weil es ein Surface ist, von ISurface ableiten. SField erbt nur von SurfaceImpl, da keine weitere Verallgemeinerung nötig ist. Somit muss ich draw nur einmal in SurfaceImpl implementieren und kann immer nach dem erwünschten Typ casten.
-
Bei der hier gezeigten Vererbungsstruktur ist doch gar kein Diamond of Death dabei. Wozu hier die ganze virtuelle Vererbung? Fehlte da was?
-
Ich habe die Warning jetzt einfach mit #pragma ignoriert, mit unter weil mir gesagt wurde, dass diese Warning bei gcc nicht kommt.
-
Mr.Long schrieb:
Nur will ich dieses Warning halt weg bekommen.
Hab die Warnung nicht.
-
Müssen die Basisklassen nicht einen virtuellen Destructor haben?
-
Mr.Long schrieb:
Wie bekomme ich das Warning weg?
Vielleicht, indem Du in der main sagst, welches func Du meinst.
d.B::func();#include <iostream> class Boot { double masse; public: void virtual fahr() = 0;//Jedes Boot kann fahren! }; class MotorBoot : public virtual Boot { double hubraum; public: void virtual fahr() {std::cout << "brumm brumm" << std::endl;}//Mit Motorbetrieb }; class SegelBoot : public virtual Boot { double segelflaeche; // void virtual fahr() {std::cout << "rausch rausch" << std::endl;}//Mit Windbetrieb }; class MotorSegler : public MotorBoot, public SegelBoot { //fahr weggelassen, weils hier unklar ist, wie gefahren wird, kann beides, aber nicht //beides zugleich! }; int main() { MotorSegler d; d.MotorBoot::fahr();//fahr wie ein Mototboot, macht brumm brumm // d.SegelBoot::fahr();//sei doch mal ein Segelboot und fahr, macht rausch rausch, wenns endlich mal implementiert wurde!!! // d.MotorSegler::fahr();//kann sich nicht entscheiden // d.fahr();//kann sich ebenso nicht entscheiden return 0; }