通过成员指针访问受保护的成员:这是一个黑客?

YSC*_*YSC 52 c++ protected access-specifier member-pointers language-lawyer

我们都知道protected从基类指定的成员只能从派生类自己的实例访问.这是标准的一个特性,这已在Stack Overflow上多次讨论:

但似乎有可能用成员指针来解决这个限制,因为用户chtz 向我展示:

struct Base { protected: int value; };
struct Derived : Base
{
    void f(Base const& other)
    {
        //int n = other.value; // error: 'int Base::value' is protected within this context
        int n = other.*(&Derived::value); // ok??? why?
        (void) n;
    }
};
Run Code Online (Sandbox Code Playgroud)

coliru现场演示

为什么这可能,它是一个想要的功能或实施中的某个地方或标准的措辞?


从评论中出现了另一个问题:如果Derived::f用实际调用Base,是不确定的行为?

Oli*_*liv 30

由于访问控制[class.access],使用类成员访问 expr.ref(aclass.amember)无法访问成员的事实不会使此成员无法使用其他表达式访问.

表达式&Derived::value (其类型为int Base::*)是完全符合标准的,它指定构件valueBase.然后表达式a_base.*pwhere p指向成员Basea_base实例的指针Base也是标准兼容的.

因此,任何符合标准的编译器必须使表达式other.*(&Derived::value);定义的行为:访问会员valueother.


eer*_*ika 15

这是一个黑客?

与使用类似reinterpret_cast,这可能是危险的,并且可能是很难找到错误的来源.但它的形成良好,毫无疑问它是否应该有效.

澄清类比:行为reinterpret_cast也完全在标准中指定,可以在没有任何UB的情况下使用.但reinterpret_cast绕过类型系统,类型系统是有原因的.类似地,这个指向成员技巧的指针很好地根据标准形成,但它绕过成员的封装,并且封装(通常)存在是有原因的(我通常说,因为我认为程序员可以轻率地使用封装).

[是]在执行中的某个地方还是标准的措辞?

不,实施是正确的.这是指定语言的工作方式.

成员函数Derived可以明显访问&Derived::value,因为它是一个受保护的成员基础.

该操作的结果是指向成员的指针Base.这可以应用于参考Base.成员访问权限不适用于指向成员的指针:它仅适用于成员的名称.


从评论中出现了另一个问题:如果使用实际Base调用Derived :: f,它是否是未定义的行为?

不是UB.Base有会员.