web-dev-qa-db-fra.com

Pourquoi une classe dérivée n'appelle-t-elle pas de fonction membre protégée 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;
}

Je pensais que seuls les membres protégés de this pouvaient être utilisés et que les membres protégés d'autres instances étaient toujours inaccessibles.

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 cela, car je programme en C++ depuis un certain temps, mais je n'ai trouvé aucune explication à ce comportement.

MODIFIER:

Peu importe qu'il s'agisse de la même instance ou d'une instance différente:

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, peu importe ce que instance d'une classe est utilisé:

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

private:
    int a;
};
63
Martin Drozdik

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

La spécification de langage veut garantir que vous accédez à un membre protégé de certains sous-objet de base qui appartient à la classe dérivée. Vous n'êtes pas censé pouvoir accéder aux membres protégés de certains objets indépendants indépendants du type de base. En particulier, vous ne pouvez pas accéder aux membres protégés des objets autonomes de type base. Vous êtes uniquement autorisé à accéder aux membres protégés des objets de base qui sont intégrés dans les objets dérivés en tant que sous-objets de base.

Pour cette raison, vous devez accéder aux membres protégés via la syntaxe pointer->member, reference.member Ou object.member, Où le pointeur/référence/objet fait référence à dérivé classe.

Cela signifie que dans votre exemple, le membre protégé somethingProtected() n'est pas accessible via Base objets, Base * Pointeurs ou Base & Références, mais il est accessible via Derived objets, Derived * pointeurs et Derived & références. Votre accès simple à somethingProtected() est autorisé, car il s'agit simplement d'un raccourci pour this->somethingProtected()this est de type Derived *.

b.somethingProtected() ne respecte pas les exigences ci-dessus.

Notez que conformément aux règles ci-dessus

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

le premier appel échouera également tandis que le second sera compilé, même si les deux tentent d'accéder à la même entité.

75
AnT

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

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

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

une instance dérivée aura accès à ses propres membres protégés, mais pas à d'autres membres protégés par une instance de classe, c'est par conception.

En fait, l'accès aux membres protégés d'une autre classe, à partir d'une autre instance ou de la fonction principale est en fait à la fois sous accès public ...

http://www.cplusplus.com/doc/tutorial/inheritance/ (recherchez la table des spécificateurs d'accès pour voir les différents niveaux)

Les deux exemples prouvent la même chose par exemple:

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

ici, votre classe Derived obtient b en tant que paramètre, donc elle obtient une autre instance de base, puis parce que b.somethingProtected n'est pas public, il ne sera pas conforme ..

cela se conformera:

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

votre deuxième exemple est conforme car vous accédez à une méthode publique sur une autre classe d

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

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) Derived objets. Dans les cas qui échouent, vous essayez d'accéder au membre via un Base &, et comme cela peut faire référence à un objet qui n'est pas Derived, l'accès ne peut pas être effectué.

2
Chris Dodd

Ce que vous avez fait est illégal en C++. Un membre protégé n'est pas accessible par un objet d'une classe. Seules les fonctions membres peuvent accéder aux membres protégés. protected les membres se comportent comme des membres privés, sauf lorsqu'ils sont hérités par 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.
    }
};
1
Deepu