Почему в этом коде нельзя использовать функцию защищенного члена класса?
#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;
};
Ответы
Ответ 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.
}
};