为什么我们必须在对象的地址前面提到访问C++中类的私有成员的数据类型?

问题描述:

我试图通过指针访问私人成员。我想知道为什么我们在(int *)& t前提到dtype?为什么我们必须在对象的地址前面提到访问C++中类的私有成员的数据类型?

class Test 
{ 
private: 
    int data; 
public: 
    Test() { data = 0; } 
    int getData() { return data; } 
}; 

int main() 
{ 
    Test t; 
    int* ptr = (int*)&t; 
    *ptr = 10; 
    cout << t.getData(); 
    return 0; 
} 
+0

这是没有意义的:*** int * ptr =(int *)&t; *** –

+0

如果您需要直接访问该值,请将'data'设为公共。你可以为你的类创建访问和操作数据的方法。你应该避免直接操作自己范围之外的类的成员。 –

(int*)&t:投射指针是指向整数

int* ptr = (int*)&t;:储存吨的指针在PTR

的访问控制系统适用于名称。它的名称是data,它是私有的,没有任何变量或关联的存储区域。换句话说,只要您不使用名称data这样做,您可以用其他方式访问该变量。

访问控制的目的是防止代码意外中断encapsulation

有时候会说C++“给你足够的绳索来挂你自己”,或者“防止墨菲而不是Macchiavelli” - 换句话说,如果你真的想要,你可以绕过访问控制。 Link to related article - GotW #76

当然,你应该尝试设计你的代码,使你不需要绕过访问控制。


在这种特殊情况下,代码是明确的。由于Teststandard layout class,因此可以确保在第一个数据成员之前没有填充,并且also guaranteed该演员生成可用于访问所述变量的指针t.data

对于更复杂的类,如果有问题的数据成员未在对象的存储空间的起始位置开始,代码可能无法正常工作。

它只能偶然地起作用。

Test是一个没有涉及继承的原始类,没有虚拟方法,没有RTTI支持编译,或其他任何可能会膨胀内存表示的东西。

在这个简单的例子中,唯一的成员变量与整个对象位于相同的地址。这是非常不安全的依赖,因为它对于任何更复杂的事情都是未定义的行为。

尝试例如现在将继承和虚拟方法引入您的测试。突然你的对象的头几个字节不再是第一个成员变量(这是编译器通常放置VPTR的地方),而且你测试了可怕的崩溃。

或者让你的成员变量为静态的,而现在你的对象本身实际上是空的,而你访问堆控制结构,而不一定立即崩溃,但堆腐败更糟糕。那么,在这种情况下,t是堆栈分配的,所以你只会损坏你的堆栈(这稍微差一些),但是如果是堆分配,这将变得至关重要。