考虑
class A {
protected:
int m;
};
class B : public A {
void foo(A& a) {
a.m = 42; // ill-formed
}
void bar(A& a) {
auto pm = &B::m;
auto pm2 = static_cast<int A::*>(pm);
a.*pm2 = 42; // is this ok?
}
};
根据[class.protected],尝试直接访问A::m
的格式不正确。但是,似乎我们总是可以使用static_cast
(?)来规避这一点,该方法允许使用指向成员的指针进行从派生到基的转换。还是不知何故是UB?
[{Coliru link显示bar
已编译]
答案 0 :(得分:4)
是的,您可以通过使用static_cast
来绕过受保护的机制。
在这种情况下,我认为这不是 不确定的行为。
通过使用static_cast
,您可以告诉编译器两件事:
您要求编译器将B
指针转换为A
指针。
您告诉编译器这样做是可以的。
对于1.编译器会进行非常有限的检查,以检查是否可以,对于static_cast
,编译器可以将其从派生转换为基数,反之亦然。所以编译器很高兴。变量或指针是受保护的还是公共的,都不属于变量或指针类型的一部分。 pm
和pm2
都不携带protected
信息。
对于2.编译器完全由您自己决定是否可以在您的设计中做出决定。这不是未定义的行为。这可能仍然不是一个好主意。 pm2
只是指向A
中int的指针。您可以将其重置为指向公开的int
中其他A
的指针。
背景是C ++中的访问控制通常是按类的,再加上protected
周围还有一些额外的规则,它们试图在每个实例的基础上提供某种级别的访问控制,但是这种保护并不完美正如您在有趣的问题中所展示的那样。