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

时间:2017-09-15 05:33:43

标签: c++ class oop pointers private

我正试图在指针的帮助下访问私有成员。我想知道为什么我们在(int *)& t前面提到dtype?

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;
}

3 个答案:

答案 0 :(得分:3)

门禁系统适用于名称。名称data是私有的,不是任何变量或关联的存储区域。换句话说,只要您不使用名称data,就可以通过其他方式访问变量。

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

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

当然,您应该尝试以不需要绕过访问控制的方式设计代码。

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

对于更复杂的类,如果有问题的数据成员没有从对象的存储空间的开头开始,则代码可能无效。

答案 1 :(得分:0)

(int*)&t:将指针强制转换为指向整数

的指针

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

答案 2 :(得分:0)

它只是偶然的机会开始。

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

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

尝试例如现在将继承和虚拟方法带入您的测试中。突然,对象的前几个字节不再是第一个成员变量(编译器通常放置VPTR的位置),并且您可以测试崩溃的可能性。

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