可以通过强制转换为布局兼容类型来访问私有成员吗?

时间:2012-07-15 18:14:38

标签: c++ casting c++11 access-control private-methods

从这个问题How is access for private variables implemented in C++ under the hood?的讨论中我提出了一个变体:可以通过强制转换并依赖布局兼容性来调用私有成员函数,而不是访问私有数据成员吗?

一些代码(灵感来自Herb Sutter的专栏Uses and Abuses of Access Rights

#include <iostream>

class X 
{ 
public:
  X() : private_(1) { /*...*/ }

private: 
  int Value() { return private_; }
  int private_; 
};

// Nasty attempt to simulate the object layout
// (cross your fingers and toes).
//
class BaitAndSwitch
    // hopefully has the same data layout as X
{   // so we can pass him off as one
public:
  int Value() { return private_; }
private:
  int private_;
};

int f( X& x )
{
  // evil laughter here
  return (reinterpret_cast<BaitAndSwitch&>(x)).Value();
}

int main()
{
    X x;
    std::cout << f(x) << "\n"; // prints 0, not 1
    return 0;
}; 

注意:这有效(至少在Ideone上)!新的C++11 Standard是否有任何方式通过依赖布局兼容性和reinterpret_cast /来提供保证或至少实现定义的方式来绕过访问控制的static_cast?

EDIT1 Ideone

上的输出

EDIT2 :在Sutter专栏中,他列出了上述代码无法保证工作的两个原因(虽然它在实践中有效)

  

a)不保证X和BaitAndSwitch的对象布局   同样,虽然在实践中他们可能总是如此。

     

b)reinterpret_cast的结果是未定义的,尽管大多数都是如此   编译器会让你尝试使用结果引用   黑客打算。

新的C ++ 11 Standard现在是否提供了这些layout / reinterpret_cast保证?

1 个答案:

答案 0 :(得分:3)

是的,您可以创建一种类型,使用与您尝试窃取的类型相同的布局,然后reinterpret_cast从该类型到您的布局兼容类型。但是,如果 ,源和目标类型都是标准布局类型,那么这只受标准保护(当然,只有它们的布局相同才能实际工作)。因此,如果源具有虚函数,则会被搞砸。

这似乎满足了萨特在这里的两个问题。标准布局规则确保两种类型都是标准布局,以相同的顺序定义相同的成员是布局兼容的(第9.2节,第17段):

  

如果两个标准布局结构(第9类)类型具有相同数量的非静态数据成员,并且相应的非静态数据成员(按声明顺序)具有布局兼容类型(3.9),则它们是布局兼容的。

reinterpret_cast的规则指定了两种标准布局类型之间转换的含义(第5.2.10节,第7段):

  

可以将对象指针显式转换为不同类型的对象指针。   当“指向T1的指针”类型的prvalue v转换为“指向cv T2的指针”类型时,如果T1和T2都是标准布局类型(3.9)和T2的对齐要求,则结果为static_cast<cv T2*>(static_cast<cv void*>(v))并不比T1更严格,或者两种类型都无效。