63 votes

Pourquoi une fonction membre protégée d'appel de classe dérivée ne peut-elle pas figurer dans ce code?

#include <iostream>

class Base
{  
protected:
    void somethingProtected()
    {
        std::cout << "lala" << std::endl;
    }
};

class Derived : public Base
{
public:
    void somethingDerived()
    {
        Base b;
        b.somethingProtected();    // This does not compile
        somethingProtected();      // But this is fine
    }
};

int main()
{
    Derived d;
    d.somethingDerived();
    return 0;
}

J'ai pensé que peut-être seuls les membres de l' this peuvent être utilisées et protégées des membres d'autres instances sont à jamais inaccessible.

Mais:

class Derived : public Base
{
public:

    void somethingDerived(Derived& d)
    {
        d.somethingProtected();  // This compiles even though d is
                                 // potentially a different instance
    }

    void somethingDerived(Base& b)
    {
        b.somethingProtected();  // This does not
    }
};

Je me sens un peu écoeuré par ce, depuis que j'ai été la programmation en C++ pour un certain temps, mais je ne pouvais pas trouver une explication à ce comportement.

EDIT:

Il n'a pas d'importance si c'est la même ou une autre instance:

int main()
{
    Derived d1, d2;          // Two different instances
    d1.somethingDerived(d2); // This compiles fine
    d1.somethingDerived(d1); // This compiles fine
    return 0;
}

EDIT2:

Il semble que quand il s'agit de droits d'accès, il n'importe pas quelle instance d'une classe est utilisée:

class Base
{
public:
    void something(Base& b)  // Another instance
    {
        ++b.a;               // But can enter private members
    }

private:
    int a;
};

76voto

AndreyT Points 139512

Même si le contrôle d'accès en C++ fonctionne sur la fonction de la classe (par opposition à l'instance de base), protected accès spécificateur a quelques particularités.

La spécification du langage veut s'assurer que vous accédez à un membre protégé de certains de la base de sous-objet qui appartient à la classe dérivée. Vous n'êtes pas censé être en mesure de l'accès des membres protégés de certains sans rapport avec des objets indépendants du type de base. En particulier, vous ne pouvez pas accès protégé les membres de autoportant objets de type de base. Vous n'êtes autorisé à accéder membres protégés de base des objets qui sont incorporés dans des objets dérivés de la base des sous-objets.

Pour cette raison, vous avez accès à des membres protégés par pointer->member de la syntaxe, reference.member ou object.member de la syntaxe, où le pointeur/référence/objet fait référence à la dérivée de la classe.

Cela signifie que dans votre exemple, les membres protégés somethingProtected() n'est pas accessible via Base objets, Base * des pointeurs ou des Base & références, mais il est accessible par le biais Derived objets, Derived * des pointeurs et Derived & références. Votre plain somethingProtected() accès est autorisé, car il est juste un raccourci pour this->somethingProtected()this est de type Derived *.

b.somethingProtected() viole les exigences ci-dessus.

Note que, conformément aux règles ci-dessus en

void Derived::somethingDerived()
{
    Base *b = this;
    b->somethingProtected();    // ERROR
    this->somethingProtected(); // OK
}

le premier appel échouera également, tandis que la seconde sera de compiler, même si les deux sont en train d'accéder à la même entité.

3voto

Dory Zidon Points 3069

Je crois que vous avez une certaine confusion sur la façon d'accéder à la base de membres de la classe. C'est seulement de cette manière:

class Derived : public Base
void drivedMethod() {
    Base::baseMethod();
}

dans votre exemple, vous essayez d'accéder à un membre protégé d'une autre instance.

un Dérivé de l'instance aura accès à ses propres membres, mais pas à une autre instance de classe des membres protégés, c'est par la conception.

En fait accéder les membres d'une autre classe, à partir d'une autre les membres de l'instance ou de la fonction principale sont en fait à la fois du droit public de l'accès...

http://www.cplusplus.com/doc/tutorial/inheritance/ (cherchez l'accès spécificateur de table pour voir les différents niveaux)

Les deux exemples montrent la même chose, par exemple:

void somethingDerived(Base& b)
    {
        b.somethingProtected();  // This does not

ici votre classe Dérivée est l'obtention de b en tant que paramètre, de sorte qu'il devient un autre exemple de base, ensuite parce que b.somethingProtected n'est pas public, il ne sera pas complie..

ce sera complie:

void somethingDerived()
{
   Base::somethingDerived();

votre deuxième exemple est conforme amende parce que vous accédez à une méthode publique d'une autre classe d

>  void somethingDerived(Base& b)
>     {
>         b.somethingProtected();  // This does not
>     }

2voto

Chris Dodd Points 39013

La classe Derived ne peut accéder au membre de base protégé que dans les objets Derived . Il ne peut pas accéder au membre dans des objets qui ne sont pas (nécessairement) les objets Derived . Dans les cas qui échouent, vous essayez d'accéder au membre via un Base & , et puisque cela peut faire référence à un objet qui n'est pas Derived , l'accès ne peut pas être effectué.

1voto

Deepu Points 4451

Ce que vous avez fait est illégal en C ++. Un membre protégé ne peut pas être accédé par un objet d'une classe. Seules les fonctions membres peuvent accéder aux membres protégés. protected se comportent exactement comme des membres privés sauf qu'ils sont hérités d'une classe dérivée. Considérez le programme ci-dessous pour comprendre la différence entre les membres privés, publics et protégés.

 class Base
{
    private:
    void somethingPrivate()
    {
        std::cout << "sasa" << std::endl;
    }
    public:
    void somethingPublic()
    {
        std::cout << "haha" << std::endl;
    }
    protected:
    void somethingProtected()
    {
        std::cout << "lala" << std::endl;
    }
};

class Derived : public Base
{
public:
    void somethingDerived()
    {
       Base b;
       b.somethingPublic();   // Works fine.
       somethingProtected();  // This is also fine because accessed by member function.
       //b.somethingProtected();  // Error. Called using object b.
       //somethingPrivate();      // Error. The function is not inherited by Derived.
    }
};
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X