Teilgraph der Klassenhierarchie zur Kompilierzeit durchlaufen



  • Hallo,

    ich habe folgende Klassenhierarchie

    class B
    {
    public:
    	virtual void check() { }
    }
    
    class D1 : public virtual B
    {
    public:
    	virtual void check() { B::check(); }
    }
    
    class D2 : public virtual B
    {
    public:
    	virtual void check() { B::check(); }
    }
    
    class DD : public D1, public D2
    {
    public:
    	virtual void check() { D1::check(); D2::check(); }
    }
    

    wobei check() überprüfen soll, ob ein Objekt in einem legalen Zustand ist. Prolem ist nun, dass, wenn ich check() für ein Objekt der Klasse DD aufrufe, B::check() sowohl von D1::check() als auch D2::check() aufgerufen wird.

    Weiss jemand, ob es eine Möglichkeit gibt, zur Kompilierzeit sicherzustellen, dass B::check() nur einmal aufgerufen wird?



  • Mal ganz davon abgesehen, dass ich das ganze Konstrukt sehr fragwürdig finde, solltest Du Dir mal virtuelle Vererbung ansehen.



  • Tachyon schrieb:

    Mal ganz davon abgesehen, dass ich das ganze Konstrukt sehr fragwürdig finde, solltest Du Dir mal virtuelle Vererbung ansehen.

    - Könntest du etwas mehr dazu sagen, warum du das für sehr fragwürdig hälst?
    - Mir ist nicht klar, wie ich mit virtueller Vererbung mein Problem lösen kann. B ist ja schon virtuelle Basis von D1 und D2, von daher hat DD nur ein Objekt der Klasse B als Oberklasse. Das Problem ist aber ja, dass ich für dieses Objekt zweimal mittelbar check() aufrufe, wenn ich DD:check() benutze



  • ingobulla schrieb:

    - Könntest du etwas mehr dazu sagen, warum du das für sehr fragwürdig hälst?

    Was soll die Polymorphie? Du benutzt überall nur B::check(). Mir verschließt sich komplett, was Du damit erreichen willst. Vielleicht solltest Du das mal erklären.

    ingobulla schrieb:

    Mir ist nicht klar, wie ich mit virtueller Vererbung mein Problem lösen kann. B ist ja schon virtuelle Basis von D1 und D2, von daher hat DD nur ein Objekt der Klasse B als Oberklasse. Das Problem ist aber ja, dass ich für dieses Objekt zweimal mittelbar check() aufrufe, wenn ich DD:check() benutze

    Das virtual habe ich irgendwie übersehen. Mal davon abgesehen: Wenn Du quallifiziert für D1 und D2 check() aufrufst, dann rufst Du es auch auf. 😉
    Hier:

    virtual void check() { D1::check(); D2::check(); }
    

    Du rufst von Hand D1::check() und D2::check() auf. Was erwartest Du da?

    Ich denke mal, Du willst eher sowas:

    class B
    {
    public:
        void check() {  }
    };
    
    class D1 : public virtual B
    {
    };
    
    class D2 : public virtual B
    {
    };
    
    class DD : public D1, public D2
    {
    } ;
    
    //...
    DD dd;
    dd.check();
    


  • Hier etwas ausführlicher: Sinn und Zweck des Ganzen ist, dieses Konstrukt zu benutzen, wenn B, D1, D2 und DD wirklich Daten enthalten. Sei also angenommen sie haben alle ein data member

    int size;
    

    und der müsse positiv sein, damit ein Objekt einer dieser Klassen in einem legalen Zustand ist.

    class B 
    { 
    private:
    	int size;
    public: 
        virtual void check() { if (size <= 0) throw Error("B in illegal state"); } 
    } 
    
    class D1 : public virtual B 
    { 
    private:
    	int size;
    public: 
        virtual void check() { B::check(); if (size <= 0) throw Error("D1 in illegal state"); } 
    } 
    
    class D2 : public virtual B 
    { 
    private:
    	int size;
    public: 
        virtual void check() { B::check(); if (size <= 0) throw Error("D2 in illegal state"); } 
    } 
    
    class DD : public D1, public D2 
    { 
    private:
    	int size;
    public: 
        virtual void check() { D1::check(); D2::check(); if (size <= 0) throw Error("DD in illegal state"); } 
    }
    

    Mit check() soll man dann überprüfen können, ob ein jeweiliges Objekt in einem legalen Zustand ist. Für ein Objekt der Klasse DD müsste also überprüft werden, ob size > 0 für DD, D1, D2 und B gilt (Konstruktoren, etc. habe ich hier weggelassen)



  • Wenns nur darum geht hier Ausführungs-Zeit spraen zu wollen würde ich sagen lass es einfach.
    So lange es kein echtes Problem verursacht (was es vermutlich nicht wird) ... zahlt es sich auch nicht aus das Problem zu lösen welches eben keines ist.



  • ingobulla schrieb:

    ...

    Ich würde die Zugriffe in den Settern / Kosntruktoren so gestalten, dass es gar keine invaliden Zustände geben kann. Dann muss hinterher auch nichts geprüft werden.


Anmelden zum Antworten