这个问题在这里已有答案:
- 访问另一个子类中的基类的受保护成员 7个答案
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