简体   繁体   English

为什么此代码允许访问私有变量

[英]Why this code allows accessing private variables

I've come across this approach (as one of the solutions to a programming task in a C++ course ) a few days ago. 几天前,我遇到了这种方法(作为C ++课程中编程任务的解决方案之一)。

#include <iostream>

struct C {
    C(int i) { m_i = i; }
private:
    int m_i;
};

template<typename Tag, int C::* M>
struct Rob {
    friend
    int C::* get(Tag) {
        return M;
    }
};

template<typename D>
struct AcessorTag {
    typedef D C::*type;
};

template struct Rob<AcessorTag<int>, &C::m_i>;

int &get_c(C &cls) {
    return cls.*get(AcessorTag<int>());
}

int main()
{
    C c(13);
    std::cout << get_c(c);
    return 0;
}

Can you please explain why this code compiles? 您能否解释一下为什么编译此代码? Pretty much all that happens here is 1) we pass pointer-to-member as an argument to a struct template 2) we declare a friend function that just returns that pointer to member. 这里发生的几乎所有事情是:1)我们将指针指向成员作为结构模板的参数传递给我们; 2)声明一个朋友函数,该函数仅将该指针返回给成员。

Is this standard C++? 这是标准的C ++吗? (I have tested on VS 2015) (我已经在VS 2015上进行了测试)

The get function is a friend of struct Rob<> but it isn't a frient of struct C . get函数是struct Rob<>的朋友,但不是struct C Anyway, struct C appears to have no friends so how come its private member is accessible? 无论如何, struct C似乎没有朋友,那么为什么它的私有成员可以访问?

Thanks! 谢谢!

Aside from missing forward declaration of get function this code should work fine and is standard compliant. 除了缺少get函数的前向声明外,此代码还可以正常工作并且符合标准。 This code works because of the special rule applied for explicit instantiation definitions of templates: 由于适用于模板的显式实例化定义的特殊规则,因此可以使用此代码:

17.8.2 Explicit instantiation [temp.explicit] 17.8.2显式实例化[temp.explicit]

14 The usual access checking rules do not apply to names used to specify explicit instantiations. 14通常的访问检查规则不适用于用于指定显式实例化的名称。 [Note: In particular, the template arguments and names used in the function declarator (including parameter types, return types and exception specifications) may be private types or objects which would normally not be accessible and the template may be a member template or member function which would not normally be accessible. [注:特别是,函数声明符中使用的模板参数和名称(包括参数类型,返回类型和异常规范)可能是私有类型或对象,通常是无法访问的,并且模板可能是成员模板或成员函数通常是无法访问的。 —end note ] —尾注]

So writing 所以写

template struct Rob<AcessorTag<int>, &C::m_i>;

will bypass usual access checks and make a pointer to otherwise inaccessible member available to get function body. 将绕过常规的访问检查,并提供指向否则无法访问的成员的指针,以get函数体。

Motivation for such a fancy rule has been nicely described in this answer . 这个答案中很好地描述了这种幻想规则的动机。

Of course, your code does not compile with gnu c++ and clang++; 当然,您的代码无法使用gnu c ++和clang ++进行编译; the identifier get is not a member of C . 标识符get不是C的成员。 Even if you try to instantiate Rob , eg 即使您尝试实例化Rob ,例如

Rob<AcessorTag<int>, &C::m_i> rob;

you obtain the 您获得

error: 'int C::m_i' is private.

You can always ask Microsoft if their c++ compiler is conforming to any standards. 您可以随时询问Microsoft他们的c ++编译器是否符合任何标准。 Let me know their answer if they answer at all. 如果他们完全回答,请告诉我他们的答案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM