无法访问受保护的成员

Cannot access protected member

本文关键字:成员 受保护 访问      更新时间:2023-10-16

我不明白下面的内容,当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?
}

一个常见的误解。

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
}

你正好碰到了标准中的一个特殊规则:

11.5受保护成员访问
当派生类的友元或成员函数引用基类的受保护的非静态成员函数或受保护的非静态数据成员时,除第11条中所述的访问检查外,还应用访问检查。除形成指向成员的指针外,*访问必须通过指向派生类本身(或从该类派生的任何类)的指针、引用或对象。

这个附加的访问检查的一个原因是关于那些基类受保护成员的行为。由于成员是受保护的,因此不同的派生类可以向这些派生成员添加语义,甚至可以对其意义进行全面更改。(这就是为什么受保护的数据相当危险的原因之一。)由于您的类不会注意到其他派生类对基类语义所做的这些添加/修改,因此最好的方法是在通过基类访问时排除对基类成员的访问。

提供别人所说的具体例子:

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
}

您的想法是正确的,但是您没有正确地使用受保护的成员。

void foo(Base* b)应该改为void foo();

,它的实现是:

void派生::foo() {返回这个-> x;}

因为x是受保护的成员,所以你不能从另一个对象访问它——即使这个对象继承了这个类。您只能从派生对象本身访问它。

您实际上所做的是创建一个base实例,它与派生的关系与派生的内部base实例的关系不同。将变量设置为protected使继承的类可以访问它自己的内部base实例。但是,在类中创建base类型的对象是不同的,因此不允许访问。