C++ - 从类外部更改私有(private)成员

标签 c++

此代码是否会导致未定义的行为?或者我可以遇到这个问题吗? (复制没有函数的完整类,只是带有 public 修饰符的变量并修改私有(private)成员抛出这个指针) 示例:

#include <iostream>

using namespace std;

class Point {

private:

    int x;
    int y;

public:

    Point(int x, int y) {
        this->x = x;
        this->y = y;
    }

    void Print() {
        cout << "(" << x << ", " << y << ")" << endl;
    }

};

struct PointHack {

    int x;
    int y;

};

int main() {
    Point a(4, 5);
    a.Print();
    ((PointHack *) (&a))->x = 1;
    ((PointHack *) (&a))->y = 2;
    a.Print();

    return 0;
}

输出:

(4, 5)
(1, 2)

(当然是用原来的成员(member)顺序)

最佳答案

尽管您的类是布局兼容的(见下文),但由于 the C++ strict aliasing rules 禁止此类指针转换,因此您的代码表现出未定义的行为1.

但是:用 union 替换强制转换使代码符合标准;这实际上保证在 C++11 中工作:

#include <iostream>

using namespace std;

class Point {

private:

    int x;
    int y;

public:

    Point(int x, int y) {
        this->x = x;
        this->y = y;
    }

    void Print() {
        cout << "(" << x << ", " << y << ")" << endl;
    }

};

struct PointHack {
    int x;
    int y;
};

union pu
{
    Point p;
    PointHack ph;
    pu(int x, int y) : p(x, y) {}
};

int main() {
    pu u(4,5);
    u.p.Print();
    u.ph.x=1;
    u.ph.y=2;
    u.p.Print();
    return 0;
}

这是因为 PointPointHack 是标准布局类2(C++11,§9 ¶7) ,并共享一个“公共(public)初始子序列”(§9.2,¶20);因此,如果它们都存储在同一个 union 中(此处为 pu),则允许“检查其中任何一个的公共(public)初始部分”3

不过,这个答案主要是一种风格练习;除非你真的被迫,否则不要利用这些技巧。 C++ 提供了更好的方法来在必要时访问私有(private)成员,而不会残酷地破坏封装——你有 getter/setter、 protected 继承、友元类……而且通常,如果你以目标类不希望的方式访问私有(private)类成员,您可能违反了该类关于如何修改其数据的假设,这可能导致其方法代码的行为不稳定。


注释:

  1. 在C++中,你不能有两个不相关类型的指针指向同一个对象;此限制主要用于帮助优化器做出关于别名的假设。
  2. 请注意,这方面的要求非常严格;通常,大多数基本上不是 C 结构的类都不符合此条件。即使有不同的访问限定符也可以打破魔法。
  3. 思路是赋值给ph使其成为union的“事件对象”,然后p.Print()就是“检查”“非事件”对象的那个。

关于C++ - 从类外部更改私有(private)成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19209535/

相关文章:

c++ - c++ 中是否有任何类是所有类的父类(super class)?

c++ - 无法编译 FSM 示例代码

c++ - "new"operator in multiple threads cause Segmentation Fault

c++ - 让 CMake 明确选择 MSVC 平台工具集

c++ - While/For 循环不会循环。 (C++)

c++ - 使用模板

c++ - 宏 `assert`会在C++20中被移除吗?

c++ - 构造线程时调用的运算符重载函数

c++ - 是否存在取消引用(但不使用)空指针以进行空引用的平台或情况会表现不佳?

c++ - 制作内核的不同方法