static und ableitung



  • Hallo zusammen,

    ich habe folgenden Sachverhalt.

    class User;
    
    class Base
    {
    protected:
    	static void Foo(){}
    };
    
    class Inherit : public Base
    {
    	friend User;
    };
    class User
    {
    
    public:
    	void Bar()
    	{
    		Base::Foo();    // ? Warum funktioniert das hier.
    		Inherit::Foo();
    	}
    };
    
    int main()
    {
    	User t;
    	t.Bar();
    }
    

    Kann mir einer von euch sagen warum das funktioniert. Ist das im Standard irgendwo beschrieben wie die statischen Funktionen bei Ableitung gehandhabt werden?

    Danke für die Hilfe.

    Grüße
    Tobi



  • User ist ein friend von Inherit. friend heißt, dass User nach Belieben in den Eingeweiden von Inherit herumwurschteln darf, das heißt es hat auf alles Zugriff, worauf Inherit Zugriff hat (mit Ausnahme der Eingeweide von Klassen, die Inherit als friend deklariert haben).
    Es hat insbesondere auch Zugriff auf die Teile von Foo, die Foo protected deklariert hat, weil die an Inherit vererbt werden.
    Merke: friend ist die engste und übelste Bindung, die du überhaupt nur haben kannst, noch enger als Vererbung. Ich benutze friend aus dem Grund so gut wie nie (kann mich an kein Beispiel erinnern wo ich es benutzen würde).

    C++ - where friends can touch your privates, but your family can't.



  • Was ist daran so verwunderlich Inherit ist ein Base!?



  • dot schrieb:

    Was ist daran so verwunderlich Inherit ist ein Base!?

    Die Frage ist doch, warum man ein Base::Foo aufrufen kann. Lässt man das static weg, gehts wie erwartet nicht:

    class User;
    
    class Base
    {
    protected:
        void Foo(){}
    };
    
    class Inherit : public Base
    {
        friend class User;
    };
    class User
    {
    
    public:
        void Bar()
        {
            Base *b;
            Inherit *i;
            i = new Inherit();
            b = i;
            b->Foo();    // ? Warum funktioniert das hier.
            i->Foo();
        }
    };
    
    int main()
    {
        User t;
        t.Bar();
    }
    

    Führt erwartungsgemäß zum Fehler:

    base.cpp: In member function 'void User::Bar()':
    base.cpp:6: error: 'void Base::Foo()' is protected
    base.cpp:23: error: within this context



  • 👍

    pumuckl schrieb:

    User ist ein friend von Inherit. friend heißt, dass User nach Belieben in den Eingeweiden von Inherit herumwurschteln darf, das heißt es hat auf alles Zugriff, worauf Inherit Zugriff hat (mit Ausnahme der Eingeweide von Klassen, die Inherit als friend deklariert haben).
    Es hat insbesondere auch Zugriff auf die Teile von Foo, die Foo protected deklariert hat, weil die an Inherit vererbt werden.
    Merke: friend ist die engste und übelste Bindung, die du überhaupt nur haben kannst, noch enger als Vererbung. Ich benutze friend aus dem Grund so gut wie nie (kann mich an kein Beispiel erinnern wo ich es benutzen würde).

    C++ - where friends can touch your privates, but your family can't.

    Hallo Pumuckl,

    danke für die Info, jetzt wird es mir klar... Der friend wurde bei uns im Review auch gefunden und wir haben uns gewundert warum es funktioniert. Wir haben einfach zu kompliziert gedacht.

    Danke 👍



  • pumuckl schrieb:

    User ist ein friend von Inherit. friend heißt, dass User nach Belieben in den Eingeweiden von Inherit herumwurschteln darf, das heißt es hat auf alles Zugriff, worauf Inherit Zugriff hat

    Seit wann ist friend transitiv? User ist ein Freund von Inherit , nicht von Base . Dass User dadurch direkt Zugriff auf Base hat, finde ich unlogisch. Lässt man nämlich die Inherit -Klasse weg, gehts nicht. Wie von manni66 hervorgehoben, gilt das Gleiche für nicht-statische Methoden.

    Steht das überhaupt so im Standard? Übrigens interessant, dass Comeau und MSVC friend statt friend class kompilieren...

    pumuckl schrieb:

    Ich benutze friend aus dem Grund so gut wie nie (kann mich an kein Beispiel erinnern wo ich es benutzen würde).

    Strikte Kapselung ist in der Theorie ja schön, aber manchmal ist friend unausweichlich, wenn man seine öffentliche Schnittstelle sauber halten will. Sauber heisst, keine Funktionalität duplizieren oder nur aus technischen Gründen (andere Klassen benötigen Zugriff auf sie) anbieten.



    • friend ist nicht transitiv.
    • friend class X ist gleichzeitig eine Vorwärtsdeklaration. Wenn schon irgendwo weiter oben class X; steht ist friend X; auch gültig.
    • ...wieso das proteced static komisch spielt, ist mir auch schleierhaft 🙂

  • Mod

    KasF schrieb:

    friend class X ist gleichzeitig eine Vorwärtsdeklaration.

    Das ist im Prinzip richtig, aber ohne Relevanz. Eine friend-Deklaration injiziert nämlich den entsprechenden Nahmen nicht in den umliegenden Namensraum, dieser Name wird also weder durch qualifiziertes noch durch unqualifiziertes Lookup gefunden werden.


Log in to reply