Zugriff auf protected Variable



  • KPC schrieb:

    Danke das erklärts!

    Glaube nicht, dass das die Erklärung dafür ist.

    base ist eine freie Variable innerhalb der Funktion, d.h. die abgeleitete Klasse hat keine Sonderrechte auf diese freie Variable, auch wenn es sich dabei um ein Objekt der Basisklasse handelt.



  • Korrektor schrieb:

    KPC schrieb:

    Danke das erklärts!

    Glaube nicht, dass das die Erklärung dafür ist.

    base ist eine freie Variable innerhalb der Funktion, d.h. die abgeleitete Klasse hat keine Sonderrechte auf diese freie Variable, auch wenn es sich dabei um ein Objekt der Basisklasse handelt.

    Aber mit der konkreten, oder speziellen Formen geht es?



  • David_pb schrieb:

    Aber mit der konkreten, oder speziellen Formen geht es?

    😕 Was meinst du?



  • Korrektor schrieb:

    David_pb schrieb:

    Aber mit der konkreten, oder speziellen Formen geht es?

    😕 Was meinst du?

    Ich meine die spezielle Form A oder weiter spezialisierte Formen von A.



  • David_pb schrieb:

    Ich meine die spezielle Form A oder weiter spezialisierte Formen von A.

    Wie würde ein lauffähiges Beispiel aussehen?



  • Hab doch oben eins gepostet. Und auch das Beispiel von KPC funktioniert wenn Base durch A getauscht wird.



  • David_pb schrieb:

    class Base
    {
    protected:
      int var;
    };
    
    class B;
    
    class A : public Base
    {
    protected:
      void func( const B &base);
    };
    
    class B : public A
    {
    };
    
    void A::func( const B& base )
    {
    	int i = base.var;
    }
    

    Fügt man B noch ein protected Member hinzu kann A auf dieses nicht zugreifen auf das Member des Basisklassenobjekts aber schon.

    Warum funktioniert dieses c++ Hackfleisch von david_pb? Kann das einer erklären?


  • Mod

    Wie schon gesagt: protected erlaubt den Zugriff auf das Member in abgeleiteten Klassen, wenn es zum Basisklassensubobjekt der abgeleiteten Klasse gehört - diese Zugriffsspezifikation ist also klassen- und objektbezogen.
    Dabei genügt indirekte Ableitung (sofern wenigstens ein geeigneter Konvertierungspfad existiert).
    Umgekehrt hat eine Basisklasse (abgesehen von friend-Fällen) keine besonderen Zugriffsrechte auf eine abgeleitete Klasse.

    class A { protected: int x; };
    class B : virtual private A {};
    class C : virtual public A {};
    class D : B,C { void foo(); };
    void D::foo()
    {
        A& a = *this;
        B& b = *this;
        C& c = *this;
        D& d = *this;
        a.x = 0; // Fehler
        b.x = 0; // Fehler, A ist private Basis von B
        c.x = 0; // ok
        d.x = 0; // ok, der Konvertierungspfad D->C->A ist möglich; D->B->A ist nicht zulässig, würde aber zum gleichen Ergebnis führen
                 // wäre A keine gemeinsame virtuelle Basis, wäre der Zugriff mehrdeutig, obwohl für den Pfad über B keine Rechte existieren
    


  • Wieso ist

    c.x = 0;
    

    OK?



  • Zu David_pbs Konstruktion kann ich irgendwie keine Erklärung finden. Vermutlich stehe ich auch auf dem Schlauch.

    class Base {protected: int x; };
    
    class C;
    
    class A : public Base {};
    
    class B : public A { void foo(); };
    
    class C : public B {};
    
    void B::foo(){
    
    	Base myBase = Base();
    	A myA = A();
    	B myB = B();
    	C myC = C();
    
    	//myBase.x = 0; // diese Fehler dürfte klar sein
    	//myA.x = 0;    // der hier auch
    	myB.x = 0;   // das funktioniert, weil myB ein Objekt der eigenen Klasse ist
    	myC.x = 0;   // Aber warum funktioniert das ? 
    }
    

    Ist mir irgendwie noch nie begegnet, vielleicht kapiere ich es deswegen nicht. 😃


  • Mod

    Mitleid schrieb:

    Wieso ist

    c.x = 0;
    

    OK?

    ist es nicht, denn das c muss ja nicht mit einem D-Objekt verwandt sein.
    Kleine Verwechselung beim Erstellen des Beispiels, sollte so aussehen:

    class D;
    class A { protected: int x; };
    class B : virtual private A {};
    class C : virtual public A {void foo(D& bar);};
    class D : public B, public C {};
    void C::foo(D& bar)
    {
        A& a = bar;
        B& b = bar;
        C& c = bar;
        D& d = bar;
        a.x = 0; // Fehler
        b.x = 0; // Fehler, A ist private Basis von B
        c.x = 0; // ok
        d.x = 0; // ok, der Konvertierungspfad D->C->A ist möglich; D->B->A ist nicht zulässig, würde aber zum gleichen Ergebnis führen
                 // wäre A keine gemeinsame virtuelle Basis, wäre der Zugriff mehrdeutig, obwohl für den Pfad über B keine Rechte existieren
    }
    

    Das sind eben Sachen, die man praktisch eh nicht macht, protected ist imo eigentlich weitgehend überflüssig.



  • Das ist wirklich eine recht spezielle Regelung im Standard. Wieso ist gerade protected teilweise ein Ausnahmefall mit objektbezogenem Zugriff?



  • @camper

    OK, nun leuchtet mir

    c.x = 0;
    

    ein, denn es ist ja wieder ein Objekt der eigenen Klasse. Aber

    d.x = 0;
    

    ist mir noch immer schleierhaft. Und seltsamerweise lässt VC das auch nicht mehr durchgehen, während MinGW nicht meckert. 😕

    Wäre schön wenn David_pb vielleicht noch das eine oder andere Wort zu seiner Kreation sagen könnte. 😉

    @Nexus
    Könntest du kurz den Paragraphen im Standard bzgl. protected benennen, damit ich das nachlesen kann.

    Das sieht mir irgendwie alles nicht "koscher" aus. Wenn ich mich trauen würde, würde ich UB sagen. 😃



  • Das ist ja im Endeffekt der Fall d.x = 0 aus camper's Beispiel.

    class B; 
    
    class Base 
    { 
    protected: 
        int i; 
    }; 
    
    class Other : public Base
    {
    protected:
        void func( const B& );
    };
    
    class A : public Base 
    { 
    protected: 
        void func( const B& ); 
    }; 
    
    class B : public A 
    { 
    }; 
    
    void A::func( const B& b ) 
    { 
        const Base* b1 = &b;
        const A* b2 = &b;
        const B* b3 = &b;
    
        Other foo;
        b1 = &foo; // b1 kann auch auf ein 'nicht-A' Objekte zeigen
    
        int i = b1->i; // Fehler
        i = b2->i; // Ok - 'ist ein' A
        i = b3->i; // Ok - 'ist ein' A
    }
    
    void Other::func( const B& b)
    {
        int i = b.i; // base ist kein 'Other'!
    }
    

    Interessant finde ich folgendes:

    class B; 
    
    class Base 
    { 
    protected: 
        int i; 
    }; 
    
    class A : private Base 
    { 
    protected: 
        void func( const B& ); 
    }; 
    
    class B : public A 
    { 
    }; 
    
    void A::func( const B& b ) 
    { 
        const Base* b1 = &b;
        const A* b2 = &b;
        const B* b3 = &b;
    
        int i = b1->i; // Fehler
        i = b2->i; // Ok
        i = b3->i; // Ok 
    }
    

    Im Standard kannst dus unter 11.5 - Protected member access [class.protected] nachlesen.



  • David_pb schrieb:

    const A* b2 = &b;
        const B* b3 = &b;
        // ...
        i = b2->i; // Ok - 'ist ein' A
        i = b3->i; // Ok - 'ist ein' A
    }
    

    Hm, das scheint mir anschaulich logisch.

    Allerdings funktioniert, wie gesagt, in campers Beispiel das d.x = 0 mit dem Microsoft Compiler nicht, obwohl man dort doch auch annehmen könnte, dass das D ein C ist. 😕

    Hab 11.5 überflogen, aber zu deinem Beispiel wird da, soweit ich es erkennen konnte, nichts gesagt.

    Aber gut, wie auch immer, ist sowieso eine ungewöhnliche Konstruktion ... 🙂


Anmelden zum Antworten