Zugriff verweigert auf protected Element



  • Wie meine Vorredner schon erwähnten, hast du den static member "*ptr" nicht initialisiert. Zusätzlich ist das mit dem Zeiger eine ganz gefährliche Sache, da er komplett auf a zeigt. Probiere es mal so:

    #include <iostream>
    
    class a {
        protected:
        a *ptr;
        virtual void exec() { std::cerr << "message from a" << std::endl;}
    
        public:
        a() { ptr = this; }
        void func();
    };
    
    void a::func() {
        ptr->exec();
    }
    
    class b : public a {
        protected:
        void exec() { std::cerr << "message from b" << std::endl;}
    
        public:
        void func();
    };
    
    void b::func() {
        a::exec(); 
        exec();
    }
    
    int main(int argc, char* argv[]) {
        b my_obj;
        my_obj.func();
        system("Pause");
        return 0;
    }
    


  • satanfreze schrieb:

    Wie meine Vorredner schon erwähnten, hast du den static member "*ptr" nicht initialisiert. ...

    schreibst du doch selbst
    =>

    satanfreze schrieb:

    ...
    class a {
    ...
        a() { ptr = this; }
    ...
    };
    ...
    int main(int argc, char* argv[]) {
        b my_obj; // -> b::b() -> a::a() => a::ptr ist initialisiert
    ...
    

    Gefährlich wäre natürlich der Zugriff auf das statische a::ptr von außerhalb ... aber dagegen will sich pro_develop vermutlich dadurch absichern, dass er es protected macht.

    Schwieriger finde ich da ja (neben der fehlenden Multithreadingfähigkeit), dass bei diesem Design einem konkreten B-Objekt "unter der Hand" ein anderes untergeschoben wird:

    int main() {
       b b1; // b1::a::ptr verweist auf b1::a 
       b b2; // b1::a::ptr verweist auf b2::a !!
    

    Aber es kann sein, dass die o.g. "protected-Besonderheit" genau dagegen schützen will...

    Gruß,

    Simon2.



  • Danke für die vielen Antworten 🙂

    Beim Tippen des vereinfachten Beispiels ist mir wohl der statische pointer durch die Lappen gegangen, deshalb hier noch einmal mein Codebeispiel.

    @hustbear: Ich habe nun die exec() funktion in b rausgenommen, so greife ich über den Zeiger auf a auf die Funktion in der Basisklasse zu. Das Problem bleibt das selbe.

    @Dweb: ich finde die Schreibweise aus C mit Konstruktor(void) besser ...

    @Simon2: ich benötige dieses Design, um eine C/C++ Adaption auf eine Library zu realisieren, daher soll das ganze auch diese Form haben ...
    Dein erster Ansatz finde ich ganz gut ... aber ich möchte doch auf exec() in a zugreifen, wo doch auch der static pointer drin ist ???????? 😕

    #include "stdafx.h"
    
    #include <iostream>
    
    using namespace std;
    
    class a
    {
        protected:
        static a *ptr;
        virtual void exec(void) {cerr << "message from a" << endl;}
    
        public:
        a(void) {ptr = this;}
        static void func(void);
    };
    
    a *a::ptr = NULL;
    
    void a::func(void)
    {
        ptr->exec();
    }
    
    class b : public a
    {
        protected:
        //void exec(void) {cerr << "message from b" << endl;}
    
        public:
        static void func(void);
    };
    
    void b::func(void)
    {
        ptr->exec();  // error C2248: 'a::exec': Kein Zugriff auf protected Element, dessen Deklaration in der Klasse "a" erfolgte
    }
    
    int main(int argc, _TCHAR* argv[])
    {
    	return 0;
    }
    


  • pro_develop schrieb:

    aber ich möchte doch auf exec() in a zugreifen, wo doch auch der static pointer drin ist ?

    Simon2 schrieb:

    Diese Besonderheit von protected ist mir auch erst ziemlich spät aufgefallen: Man darf nur auf das "eigene a" zugreifen. Das ist aber über den statischen Zeiger ptr nicht mehr gewährleistet.

    hustbaer schrieb:

    Wenn du sicher weisst dass "ptr" ein "b" ist, dann kannst du den Fehler mit einem static_cast umgehen.

    void b::func(void)
    {
        static_cast<b*>(ptr)->exec();  // aber nur, wenn "ptr" wirklich auf ein "b"-Objekt zeigt.
    }
    


  • tut mir leid ... ich hab's noch nicht kappiert 😕

    wenn ich den ptr auf a mit dem this-zeiger auf b initialisiere, dann zeigt
    dieser doch auf das Basis-Objekt (Teil a) des b-Objekts ... dann sollte es doch möglich sein, eine Member-Funktion von a aufzurufen .... 😞



  • Du darfst nur direkt mit einem Objekt von B auf die protected-Teile von A zugreifen. Jedoch nicht mit einem Objekt von A oder Zeiger auf A.

    class Base
    {
        protected:
           int test;
    };
    
    class Derived : public Base
    {
        void func();
    };
    
    void Derived::func()
    {
       Base* ptr = new Base();
       cout << ptr->test; // Nicht erlaubt
       cout << test;      // Ist erlaubt, entspricht ja ( this->test )
    }
    

    Die abgeleitete Klasse hat keinen Sonderzugriff auf protected Elemente von Base. Sie darf nur über ein Objekt von sich selbst drauf zu greifen.

    Verstanden 😉 ?

    Lg freeG



  • Hab dir mal ein kleines Beispiel gemacht:

    class A
    {
        protected:
            int i;
    };
    
    class B : public A
    {
        public:
            void fkt()
            {
                A a_objekt;
    
                B b_objekt;
    
                A* ptr;
    
                /*
                    Fehler:
                        Innerhalb der "Klasse B" darfst du nur von einem "B-Objekt" aus
                        auf die protected-Teile von A zugreifen.
                        Wenn der Zeiger aber auf ein "A-Objekt" verweist,
                        ist es ein Zugriff von außerhalb, und das erlaubt protected nicht.
                */
                ptr = &a_objekt; // Dieses Objekt hat nichts mit der "Klasse B" zu tun...
                ptr->i; // ...und du befindest dich außerhalb von "Klasse A" --> Fehler
    
                /*
                    "b_objekt" beinhaltet einen "A-Teil".
                    ( Es wird ja der Konstruktor der "Klasse A" aufgerufen,
                     wenn du ein "B-Objekt erstellst. )
                */
                ptr = &b_objekt; // Es ist ein "B-Objekt"...
                ptr->i; // ...Du bist innerhalb der "Klasse B" --> Zugriff erlaubt
            }
    };
    
    int main()
    {
        return 0;
    }
    


  • Danke für eure Hilfe 🙂

    Danke fr33g, mit deiner Erklärung hab ich's jetzt kappiert 🙄

    ich hab auch noch einen anderen Test gemacht:

    a hugo;
    
        a *ptr = &hugo;
    
        ptr->exec();
    

    damit taucht genau das gleiche Problem auf ...

    Wow ... ich hätte nicht gedacht, dass der Zugriffsschutz so komplex ist ...
    damit kann man sich ja regelrecht aussperren 😃

    das bedeutet also, dass einzelne Objekte einer Klasse auch gegenseitig vor Zugriffen auf die zugehörigen private oder protected Member geschützt sind ...



  • pro_develop schrieb:

    das bedeutet also, dass einzelne Objekte einer Klasse auch gegenseitig vor Zugriffen auf die zugehörigen private oder protected Member geschützt sind ...

    Nein.

    class foo
    {
    public:
     void bar (foo& other)
     {
       other.n = 5; //geht
     }
    private:
     int n;
    };
    

    Die privaten Member von other können von einem anderen Objekt des gleichen Types verändert werden!

    So habe ich deine Aussage auf jeden Fall verstanden.



  • pro_develop schrieb:

    Wow ... ich hätte nicht gedacht, dass der Zugriffsschutz so komplex ist ...
    damit kann man sich ja regelrecht aussperren 😃

    Ohne diese "Komplexität" könnte man protected sofort aushebeln, der "Schutz" wäre nicht-existent:

    // base.cpp
    
    class base
    {
    protected:
        int m_i;
    };
    
    // schummler.cpp
    
    class schummel_helper : public base
    {
    public:
        static void set_m_i(base& b, new_i_value)
        {
            b.m_i = new_i_value; // wäre schlecht wenn das erlaubt wäre...
        }
    };
    
    void schummeln(base& b, int new_i_value)
    {
        // man könnte so b.m_i setzen, obwohl dies eine freie funktion ist, die vererbungsmässig so überhaupt gar nix mit "base" zu tun hat
        schummel_helper::set_m_i(b, new_i_value);
    }
    


  • hustbaer schrieb:

    Ohne diese "Komplexität" könnte man protected sofort aushebeln, der "Schutz" wäre nicht-existent

    Diese Sonderregel hat aber auch Nachteile, welche einen zu teilweise nicht sehr sauberen Workarounds zwingt.

    Siehe z.B. in einem älteren Thread von mir (gerade am Anfang).



  • @Nexus: ich denke besser so als anders rum.



  • Es schadet nie, etwas von mehreren Seiten zu betrachten 😉



  • Natürlich nicht.
    Manchmal bringt es aber auch nix, weil ein Fall gänzlich klar ist (und auch nach weiterer Betrachtung bleibt) 😉


Anmelden zum Antworten