问题 为什么我不能从基类的实例访问受保护的成员? [重复]


这个问题在这里已有答案:


6160
2018-04-03 21:26


起源

与...一样 stackoverflow.com/questions/3060572/... - Eugene K
删除了编辑,因为问题与编译器错误无关 本身,更多的是关于规则“无法从基类访问受保护的成员”的基本原理 - Cássio Renan
@EugeneK没有。我知道我无法从基类访问受保护的成员。我的问题是为什么我不能。 - Cássio Renan
我认为编译器错误对于理解问题至关重要,你应该把它放回去。或者至少,在有效的行和失败的行上添加注释。 - Mark Ransom
既然你提到它,是的,这确实有帮助。 - Cássio Renan


答案:


你可以访问 protected 基类的成员只能通过指向或派生类型的对象的引用。

如果你改变了

void copy_a_from_bar(bar& o){
  a = o.a;
}

void copy_a_from_bar(bar& o){
  foo& foo_ref = o;
  a = o.a;        // OK. Accessing it through `bar&`
  a = foo_ref.a;  // Not OK. Accessing it through `foo&`
}

你会看到同样的错误。

这个答案 给出了为什么允许访问的原因 protected 基类成员将是一个潜在的违反 protected 基类成员的状态。

说你有:

class baz : public foo
{
   void update_a(foo& f)
   {
      f.a = 20;
   }
};

并使用:

bar x;
baz z;
z.update_a(x);

如果这是允许的, baz 将能够改变成员的价值观 bar。这是不好的。


6
2018-04-03 21:32



你对这种行为背后的理性有什么了解吗? - MikeMB
我不知道......你基本上是把这个问题转录成答案......我对这就是为什么这样的原因更感兴趣。 - Cássio Renan
为了确保这一点 只要 派生类可以访问基类的受保护数据。 - haavee
理由对我来说很明显, protected 表示它可以被派生对象访问,但是如果你有任意对象 foo 编译器无法知道是否可以 foo 是一些基类 bar 或者只是一个 foo。 - Jonathan Wakely


protected 意味着可以访问它 作为会员 在派生类中。确实如此  授予派生类不受限制的访问权限。

推理(我推测)是因为派生类可以修改基类型以维护派生类型自己的契约。但是,它不需要访问受保护的成员 其他 派生类,因为它可能会失效  合同。

合同是对成员国家的承诺。您可能熟悉的一些示例合同位于字符串的内部: size 包含缓冲区中字符串的长度,以及 buffer[size] 包含null(这里有大量的技术细节,但它们并不重要)。此外,缓冲区始终指向null或具有唯一所有权的有效以null结尾的字符串。字符串类很难确保无论怎样,所有这些都是真的。 (字符串实际上没有任何这些合同,因为它的成员是私有的,这只是一个例子)


3
2018-04-03 21:49





这是一个常见的误解 protected 手段。这并不意味着您可以从派生类型访问基类型的任何对象的成员,而只能访问属于派生类型的对象的子对象。

理由是您可以控制对象的成员,在那里您知道自己在做什么,但不会轻易搞乱其他对象的状态。考虑这个例子,在哪里 CachedDoubleValue 使用基础对象中值的两倍来维护缓存值:

class Base {
protected:
   int x;
};
class CachedDoubleValue : public Base {
   int y;
public:
   void set(int value) {
      x = value;
      y = 2 * x;
   }
};
class AnotherDerived : public Base {
public:
    static void setX(Base &b, int value) {
       b.x = 10;
    }
};
int main() {
    CachedDoubleValue a;
    a.set(1);             // a.x = 1, a.y = 2
    AnotherDerived::modifyX(a, 10);
        // Invariant broken: a.x = 10, a.y = 2; a.x != 2 * a.y
}

2
2018-04-03 21:52