Не удается получить доступ к защищенному члену
Возможный дубликат:
не может вызвать функции, защищенные базовым классом?
Я не понимаю следующее, когда Derived
наследует от Base
, он получает доступ к его защищенным членам, к которым можно получить доступ через производные функции. Но если класс Base
пытается получить доступ к своим членам из класса Derived
(который сам разрешает доступ к Base
), он не получает доступ, почему?
class Base {
protected:
int x;
};
class Derived : Base {
public:
void foo(Base* b);
};
void Derived::foo(Base* b) {
b->x = 2; // cannot access protected member,
// though Derived inherits from Base, why?
}
Ответы
Ответ 1
Общее недоразумение.
Внутри Derived::foo()
вы можете получить доступ к защищенным базовым членам объектов класса Derived
. Однако *b
не имеет типа Derived
. Скорее, он имеет тип Base
, и поэтому он не имеет ничего общего с вашим классом.
Другое дело, если вы возьмете Derived*
в качестве аргумента - тогда у вас действительно будет доступ к защищенным базовым членам.
Пусть написано:
struct Derived;
struct Base
{
int f(Derived *);
protected:
int x;
private:
int y;
};
struct Derived : public Base
{
int g(Base *);
int h(Derived *);
};
int Derived::g(Base * b)
{
return b->x; // error, protected member of unrelated class
return b->y; // error, private member of different class
}
int Derived::h(Derived * d)
{
return d->x; // OK, protected base member accessible in derived class
return d->y; // error, private member of different class
}
int Base::f(Derived * d)
{
return d->x; // OK, d converts to Base*
return d->y; // OK, ditto
}
Ответ 2
Вы запускали smack dab в специальное правило в стандарте:
11.5 Доступ к защищенному члену
Когда функция друга или члена производного класса ссылается на защищенную нестатистическую функцию-член или защищенный нестатический элемент данных базового класса, проверка доступа применяется в дополнение к тем, которые описаны ранее в разделе 11. За исключением случаев, когда формируется указатель на член, * доступ должен быть через указатель на, ссылку или объект самого производного класса (или любого класса, полученного из этого класса).
Одна из причин этой проверки доступа к добавлению связана с поведением тех защищенных членов базового класса. Поскольку члены защищены, другой производный класс может добавлять семантику или даже делать оптовые изменения в значении этих полученных членов. (Это одна из причин того, что защищенные данные довольно опасны.) Поскольку ваш класс не обращает внимания на эти дополнения/модификации семантики базового класса, сделанные в других производных классах, лучше всего сделать это, чтобы исключить доступ к элементам базового класса, когда доступ будет осуществляться через базовый класс.
Ответ 3
У вас есть правильная идея, но вы не используете защищенный элемент правильно.
void foo (Base * b) вместо этого должен быть void foo();
и его реализация будет:
void Derived:: foo() { return this- > x;
}
Поскольку x является защищенным членом, вы не можете получить к нему доступ из другого объекта - даже если этот объект наследуется от этого класса. Вы можете получить доступ к нему только из самого производного объекта.
Ответ 4
Чтобы дать конкретный пример того, что говорят другие:
class Base {
protected:
int x;
};
class Derived : Base {
public:
void foo(Derived*, Base*);
};
int main() {
Base fiddle;
Derived fast, furious;
fast.foo(&furious, &fiddle);
}
void Derived::foo(Derived *d, Base* b) {
x = 1; // Legal, updates fast.x
this->x = 2; // Legal, updates fast.x
d->x = 3; // Legal, updates furious.x
b->x = 4; // Error, would have updated fiddle.x
}
Ответ 5
Что вы по существу сделали, создается экземпляр базы, который имеет другое отношение к производному, чем внутренний экземпляр базы внутри производного. Установка переменной в protected дает унаследованному классу доступ к собственному внутреннему экземпляру базы. Однако создание объекта типа базы в классе является чем-то другим и, следовательно, не разрешает доступ.