Mehrfachvererbung -> Klasse trotz definitionen abstrakt
-
Hallo
ich habe eine klassenhierarchie bei der ich mehrfachvererbung einsetze.
(ja böse)Ref Element --> Box // interfaces | / | | / | V V v CRef --> CElement --> CBox // implementation
die oberen interfaces sind öffendlich, die unteren klassen nicht.
"Ref" ist eine Schnittstelle die sich um die referenzzählung kümmert
"CRef" ist die implementationsklasse, damit man die zählung nicht in jeder
klasse neu schreiben muss. Per template-parameter wird eine weitere basisklasse
bestimmt, denn nur wenn CRef ableitet, werden die abstrakten methoden
überschrieben und nicht andersherum.von Ref leitet jede klasse ab, von der später objekte erstellt werden.
Ref und CRef sollten also möglichst nicht geändert werden."Element" ist eine basisklasse für verschiedene elemente und CElement deren
implementation."Box" ist das interface der zu benutzenden klasse und
"CBox" deren implementation.Wenn ich direkt von CRef ableite gibt es keine Probleme.
Allerdings findet er in CBox keine der methoden aus CElement, obwohl
CElement diese methoden definiert.code:
struct Refcounting { }; template <class parent> class CRefcounting : virtual public Refcounting, virtual public parent { }; struct Element : virtual public Refcounting { virtual void func() = 0; }; class CElement : virtual public CRefcounting<Element> { void func(); }; struct Box : public Element { }; class CBox : virtual public Box, public CElement { }; void CElement::func() { } int main() { CBox c; }
Fehler:
error C2259: 'CBox': Instanz von abstrakter Klasse kann nicht erstellt werden 1> aufgrund folgender Member: 1> "void Element::func()": ist abstrakt
warum findet er meine methoden nicht, und was kann man dagegen tun?
-
Aber Box implementiert die Methode nicht...
-
muss sie ja nicht, sie wird doch von CElement übernommen?
-
Nein!
-
In
CBox
gibt es zwei Funktionenfunc
. Eine ist abstrakt die andere nicht.
Die erste Funktion kommt überCElement
rein und ist definiert.
Die zweite Funktion kommt über die KlasseBox
rein, welche nicht virtuell vonElement
erbt. Dadurch existieren zweiElement
Basisklassen inCBox
und somit die zweite Funktion, welche aber nicht definiert wurde.Grüssli
-
ok aber eigentlich müsste doch die definierte funktion die abstrakte überschreiben?
wenn ich mein programm kompiliere bekomme ich viele solcher meldungen wie:... erbt CElement::diesunddas via dominanz
ich dachte das klappt immer :|
-
der erbe schrieb:
ok aber eigentlich müsste doch die definierte funktion die abstrakte überschreiben?
Nein, Element und CElement haben nix miteinander zu tun. Du kannst keine Funktion eines Geschwisters überschreiben...
Der Unterschied Element und CElement ist nur in Java nötig, weil dort Interfaces keine Implementierung haben können. in c++ brauchst du diese Trennung nicht. Das löst übrigens auf einen Schlag deine Mehrfachvererbung.
-
d.h. einfach die abstrakten methoden implementieren?
ok aber findet er sie dann? das interface ist ja immernoch abstrakt.
-
also findet im sinne von lässt sich instanzieren.
allerdings können die methoden von Element nicht auf die member zugreifen,
die ja erst in CElement existieren.außerdem dachte ich, dass die methoden von der klasse genommen werden, von der
man zuerst erbtclass c : public erster, public zweiter
nunja..
wie muss den die klassenhierachie eurer meinung nach aussehen?
-
Ich würds so machen... mit interface müssen nicht unbedingt virtuals gemeint sein...
class refcounted { // refcounted interface }; class element : public refcounted { // element interface // (refcounted implementation) // Hier oder unten }; class box : public element { // box interface // element interface implementation, (refcounted implementation) }; int main() { box mybox; return 0; }
-
ich will ja grade durch die mehrfachvererbung die erneute implementation
verhindern. abstrakte klassen habe ich gewählt, damit der benutzer keine
implementationsdetails sieht. die interfaces sollten eigentlich nicht
verändert werden, dachte mir dass das irgentwie durch geschickte vererbung
möglich wäre.
-
der erbe schrieb:
ich will ja grade durch die mehrfachvererbung die erneute implementation
verhindern.Ne, das macht irgendwie keinen Sinn.
Mehrfachvererbung ist etwas gutes, aber nicht wenn man 2 mal von der selben klasse erbt. Deine abstrakten klassen und deine interfaces sind eine sinnlose trennung die in java technisch notwendig ist. in c++ nimmst du gleich abstrakte klassen und brauchst keine interfaces. c++ hat ja auch garkeine java-interfaces.
in java wuerdest du es so machen weil eine Box ja uU von einer anderen Klasse auch noch erben will. in c++ kann sie das aber sowieso. deshalb nimm diese hierachie:
Ref
- Element
- - BoxDu brauchst keine interfaces.
-
Vielleicht sollte der erbe ja mit Fenixx eine Lerngruppe aufmachen?
-
Shade Of Mine schrieb:
Du brauchst keine interfaces.
ich will aber nach außen ein feinsauberes interface anbieten, zum einen damit
der stil mit den anderen ~20 klassen übereinstimmt, der code erweiterbar ist,
ohne die header + benutzende programme zu ändern und damit keiner an den
privaten membern rumpfuscht.die interfaces müssen sein
-
Was ist denn daran erweiterbarer, wenn du die erweiterbarkeit aktiv unterbinden möchtest?
-
der erbe schrieb:
ich will aber nach außen ein feinsauberes interface anbieten, zum einen damit
der stil mit den anderen ~20 klassen übereinstimmt, der code erweiterbar ist,
ohne die header + benutzende programme zu ändern und damit keiner an den
privaten membern rumpfuscht.die interfaces müssen sein
Interfaces in C++ != Interfaces in Java
fuers verstecken der implementierung, also fuer compiler firewalls, nimmt man das pimpl idiom.
Interfaces in C++ sind abstrakte Klassen.
Du hast jetzt 2x abstrakte Klassendas passt halt einfach nicht.
dein design ist fuer java ok - aber C++ ist eben nicht java...
-
ich versuche den header abstrakt zu halten, damit ich in der entsprechenden
dll eine methode ändern kann, ohne das alle programme, die die dll verwenden
neu geschrieben werden müssen.das geht aber nur wenn der header mit den interfaces keine implementations-
details preisgibt. außerdem siehts unschön aus, wenn da noch datenmember drin
sind.das geht nur mit pure virtuellen funktionen.
-
der erbe schrieb:
das geht nur mit pure virtuellen funktionen.
pimpl idiom
PS:
wenn sich das public interface einer dll nicht aendert, hat man auch keine kompatibilitaets probleme...
-
Shade Of Mine schrieb:
pimpl idiom
das ist fast schon C-frickelei
aber jetzt klappts !!!!
klappts !!auch frickelei, aber im C++ style
template<class T> class CElement : public CRefcounting<Element, T> { }; class CCheckBox : public CElement<Box> { };
ob das sicher ist (2 this-pointer, irgentwas was cross-casting benötigt, etc.)
wird sich noch zeigen
-
es klappt genau so wie es soll ohne nebeneffekte