2011 C++ Standard states在第 11.4 节中
An additional access check beyond those described earlier in Clause 11 is applied when a non-static data member or non-static member function is a protected member of its naming class ( 11.2 ) 115 As described earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C . If the access is to form a pointer to member ( 5.3.1 ), the nested-name-specifier shall denote C or a class derived from C . All other accesses involve a (possibly implicit) object expression ( 5.2.5 ). In this case, the class of the object expression shall be C or a class derived from C .
(在旧标准中,类似的措辞在第 11.5 节中。)
这条规则限制了“B 的 protected 成员可以被任何 B 或 B 的派生类访问”这一经常重复的想法。然而,解释该规则很困难,当前不同的编译器以不同方式执行该规则这一事实证明了这一点。
例如,请参阅此测试代码。我使用 Apple LLVM Compiler 4.1、GCC 4.7.2 和 Visual Studio 2010 编译了这段代码。它们报告的错误既有相似之处,也有不同之处。
class Base
{
protected:
int A;
};
class Derived : public Base
{
protected:
int B;
};
class Grandchild : public Derived
{
void access_protected(Base* b, Derived* d,
Grandchild* g, class GreatGrandchild* gg );
};
class GreatGrandchild : public Grandchild {};
void Grandchild::access_protected(Base* b, Derived* d,
Grandchild* g, GreatGrandchild* gg )
{
int* p;
Base lb;
Derived ld;
Grandchild lg;
GreatGrandchild lgg;
A = 1; // Legal...
B = 2;
Base::A = 1;
Derived::B = 2;
b->A = 1; // Illegal ALL
p = &(b->A); // Illegal ALL
lb.A = 1; // Illegal ALL
p = &(lb.A); // Illegal ALL
d->A = 1; // Illegal GCC, VS
p = &(d->A); // Illegal GCC, VS
ld.A = 1; // Illegal GCC, VS
p = &(ld.A); // Illegal GCC, VS
d->B = 2; // Illegal ALL
p = &(d->B); // Illegal ALL
ld.B = 2; // Illegal ALL
p = &(ld.B); // Illegal ALL
g->A = 1; // Legal...
g->B = 2;
lg.A = 1;
lg.B = 2;
gg->A = 1;
gg->B = 2;
lgg.A = 1;
lgg.B = 2;
}
从这些结果中我了解到:(1) 访问您自己的类和派生类的 protected 成员总是可以的; (2) 访问声明它们的基类的 protected 成员始终是非法的,但该类除外; (3) 尽管标准注意区分指向成员的指针和“对象表达式”,但标准和编译器都给予它们相同的限制; (4) 尚不清楚访问“中间”基类(示例中的 Derived
)的 protected 成员是否合法,该成员是在中间基类中声明的。
然后,我是否可以谈论我祖 parent 的 protected 成员归我 parent 所有,这让我感到困惑。没有双关语。
(为了简单和理智起见,我忽略了 friend
。)
由于 protected
是该语言的基础部分,我有动力好好理解它。请:
- 根据您对标准的解释,哪个编译器正确实现了这一点?
- 整体限制的理由是什么?为什么我不能自由访问基类的 protected 成员?它旨在避免什么具体错误?您是否知道探索此基本原理的在线讨论(最好由标准委员会举行)?
最佳答案
我会说 GCC 和 Visual Studio 是正确的。
鉴于以下情况:
class Base
{
protected:
int A;
};
class Derived : public Base
{
protected:
int B;
};
class OtherGrandchild : Derived
{
};
class Grandchild : Derived
{
void access_protected(OtherGrandchild* otherGrandchild);
};
void Grandchild::access_protected(OtherGrandchild* otherGrandchild)
{
otherGrandchild->A = 1; // Should be illegal
otherGrandchild->B = 1; // Should be illegal
Derived* derived = static_cast<Derived*>(otherGrandchild);
derived->A = 1; // Should still be illegal
derived->B = 1; // Should still be illegal
}
如果您不受限制,您可以将 OtherGrandchild
的其他私有(private)成员从 Grandchild
转换为公共(public)基类型。只能通过 friend 声明允许这种访问。
我不确定关于该主题的任何讨论,但这将是我对此的解释。
关于c++ - 深入了解 C++ protected ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14524278/