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!


  • Administrator

    In CBox gibt es zwei Funktionen func . Eine ist abstrakt die andere nicht.
    Die erste Funktion kommt über CElement rein und ist definiert.
    Die zweite Funktion kommt über die Klasse Box rein, welche nicht virtuell von Element erbt. Dadurch existieren zwei Element Basisklassen in CBox 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 erbt

    class 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
    - - Box

    Du 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 Klassen

    das 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 🙂


Log in to reply