C++ 可以通过强制转换到布局兼容类型来访问私有成员函数吗?

C++ 可以通过强制转换到布局兼容类型来访问私有成员函数吗?,c++,casting,c++11,access-control,private-methods,C++,Casting,C++11,Access Control,Private Methods,从对这个问题的讨论中,我提出了一个变体:不访问私有数据成员,可以通过强制转换和依赖布局兼容性来调用私有成员函数吗 一些代码(灵感来自Herb Sutter的专栏) #包括 X类 { 公众: X():private_u1{/*…*/} 私人: int Value(){return private} int私人诊所; }; //试图模拟对象布局的恶劣尝试 //(交叉手指和脚趾)。 // 类BaitAndSwitch //希望具有与X相同的数据布局 {//这样我们就可以把他当作一个 公众: int

从对这个问题的讨论中,我提出了一个变体:不访问私有数据成员,可以通过强制转换和依赖布局兼容性来调用私有成员函数吗

一些代码(灵感来自Herb Sutter的专栏)

#包括
X类
{ 
公众:
X():private_u1{/*…*/}
私人:
int Value(){return private}
int私人诊所;
};
//试图模拟对象布局的恶劣尝试
//(交叉手指和脚趾)。
//
类BaitAndSwitch
//希望具有与X相同的数据布局
{//这样我们就可以把他当作一个
公众:
int Value(){return private}
私人:
int私人诊所;
};
INTF(X&X)
{
//这里有邪恶的笑声
return(reinterpret_cast(x)).Value();
}
int main()
{
X;

std::cout是的,您可以创建一个类型,该类型使用与您试图从中窃取的类型相同的布局,然后
将该类型重新解释为与布局兼容的类型。但只有当源类型和目标类型都是标准布局类型时,这才受标准保护(当然,只有当它们的布局相同时,它才真正起作用。)因此,如果源代码有虚拟函数,你就完蛋了

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

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

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

对象指针可以显式转换为不同类型的对象指针。 当类型为“指向T1的指针”的PRV值转换为类型为“指向cv T2的指针”时,如果T1和T2都是标准布局类型(3.9),并且T2的对齐要求不比T1严格,或者如果任何一种类型无效,则结果为
static_cast(static_cast(v))


您可以通过
reinterpret_cast
绕过几乎任何您想要的问题;您是否在问是否有可能以定义良好的方式这样做?@OliCharlesworth是的,保证最好,实现定义次之,UB不太好。不可能。在汇编级别上,类方法只是带有隐藏“this”的全局函数参数,它不属于类实例,不能通过布局技巧访问。您没有从
f
返回值,您缺少
return
语句。@ChrisTaylor谢谢,我的错。更新了。这不违反严格的别名吗?@DeadMG:我不确定。我查看了,这似乎没有违反它们。但我不是这方面的专家。我不认为
reinterpret\u cast
可以用于布局兼容类型。在
reinterpret\u cast
的法律使用中没有提到这种情况。
#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;
};