Подтвердить что ты не робот

Почему в этом коде нельзя использовать функцию защищенного члена класса?

#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;
}

Я думал, что, возможно, только защищенные члены this могут использоваться, а защищенные члены других экземпляров навсегда недоступны.

Но:

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
    }
};

Я чувствую себя отвратительным от этого, так как я некоторое время программировал на С++, но я не мог найти объяснения этого поведения.

EDIT:

Не имеет значения, является ли он одним и тем же или другим экземпляром:

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

EDIT2:

Похоже, что когда речь идет о правах доступа, вообще не имеет значения, что используется экземпляр для класса:

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

private:
    int a;
};
4b9b3361

Ответ 1

Несмотря на то, что управление доступом на С++ работает на основе каждого класса (в отличие от базиса для каждого экземпляра), спецификатор доступа protected имеет некоторые особенности.

Спецификация языка хочет убедиться, что вы обращаетесь к защищенному члену некоторого базового подобъекта, принадлежащего производному классу. Вы не должны иметь доступ к защищенным членам некоторых несвязанных независимых объектов базового типа. В частности, вы не можете получить доступ к защищенным членам автономных объектов базового типа. Доступ к защищенным членам базовых объектов, которые встроены в производные объекты в качестве базовых подобъектов, разрешено только.

По этой причине вам необходимо получить доступ к защищенным членам через синтаксис pointer->member, reference.member или object.member, где указатель/ссылка/объект ссылается на производный класс.

Это означает, что в вашем примере защищенный член somethingProtected() недоступен через объекты Base, указатели Base * или Base &, но доступен через объекты Derived, указатели Derived * и Derived & ссылки. Ваш простой доступ somethingProtected() разрешен, так как это просто сокращение для this->somethingProtected(), где this имеет тип Derived *.

b.somethingProtected() нарушает вышеуказанные требования.

Заметим, что в соответствии с приведенными выше правилами в

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

первый вызов также завершится неудачей, а второй будет скомпилирован, хотя оба пытаются получить доступ к одному и тому же объекту.

Ответ 2

Я считаю, что у вас есть путаница в том, как получить доступ к элементам базового класса. Только так:

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

в вашем примере вы пытаетесь получить доступ к защищенному члену другого экземпляра.

Производный экземпляр будет иметь доступ к своим собственным защищенным членам, но не к другим защищенным экземпляром класса, это по дизайну.

Фактически доступ к защищенным членам другого класса, от других членов экземпляра или от основной функции на самом деле доступен как под открытым доступом...

http://www.cplusplus.com/doc/tutorial/inheritance/ (найдите таблицу спецификатора доступа, чтобы увидеть разные уровни)

Оба примера доказывают одно и то же:

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

здесь ваш класс Derived получает b как параметр, поэтому он получает другой экземпляр базы, а затем потому, что b.somethingProtected не является общедоступным, он не будет соответствовать.

это будет соответствовать:

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

ваш второй пример соответствует штрафу, потому что вы обращаетесь к общедоступному методу в другом классе d

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

Ответ 3

Класс Derived может получить доступ только к защищенному базовому члену в объектах Derived. Он не может получить доступ к члену в объектах, которые не являются (обязательно) Derived объектами. В случае сбоя вы пытаетесь получить доступ к элементу через Base &, и поскольку это может относиться к объекту, который не является Derived, доступ не может быть выполнен.

Ответ 4

То, что вы сделали, является незаконным в С++. Защищенный член не может быть доступен объекту класса. Только члены-члены могут обращаться к защищенным членам. Члены protected ведут себя точно так же, как частные члены, за исключением того, что они унаследованы производным классом. Рассмотрим приведенную ниже программу, чтобы понять разницу между частными, общественными и защищенными членами.

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.
    }
};