简体   繁体   English

C ++-从班级外部更改私人成员

[英]C++ - Change private member from outside the class

Is this code causes undefined behavior? 此代码是否会导致未定义的行为? Or can i run into a problem with this? 还是我会遇到这个问题? (copy the full class without functions, just variables with public modifier and modify the private memebers throw this pointer) example: (复制没有函数的完整类,仅复制带有public修饰符的变量,并修改私有成员抛出该指针)示例:

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

output: 输出:

(4, 5)
(1, 2)

(with the original member order, of course) (当然有原始的会员订单)

Despite your classes being layout compatible (see below), your code exhibits undefined behavior due to the fact that such pointer casts are prohibited by the C++ strict aliasing rules 1 . 尽管您的类与布局兼容(请参见下文),但是由于C ++严格的别名规则 1禁止此类指针强制转换,因此代码仍表现出未定义的行为。

But: replacing the casts with a union makes the code standard-compliant; 但是:用union替换强制类型转换使代码符合标准; this is actually guaranteed to work in C++11: 实际上保证可以在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;
}

This comes from the fact that Point and PointHack are standard-layout classes 2 (C++11, §9 ¶7), and share a "common initial subsequence" (§9.2, ¶20); 这是因为PointPointHack是标准布局类2 (C ++ 11,§9¶7),并共享“公共初始子序列”(§9.2,¶20)。 as such, if they both are stored in the same union (here pu ) it's permitted to "inspect the common initial part of any of them" 3 . 这样,如果它们都存储在同一个联合体(在此为pu )中,则可以“检查其中任何一个的公共初始部分” 3

Still, this answer is mostly an exercise of style; 不过,这个答案主要是一种风格的练习。 don't exploit such tricks unless you are really forced to. 除非您真的被迫使用,否则不要利用这些技巧。 C++ provides better means to access private members if necessary without brutally breaking the encapsulation - you have getters/setters, protected inheritance, friend classes, ... And in general, if you access private class members in ways not intended by your target class, you are potentially violating the assumptions of that class about how its data is modified, which can lead to erratic behavior of the code of its methods. C ++在必要时提供了更好的方法来访问私有成员,而又不会残酷地破坏封装-您具有吸气剂/设置器,受保护的继承,朋友类……而且通常,如果您以目标类不希望的方式访问私有类成员,您可能违反了该类关于如何修改其数据的假设,这可能导致其方法代码的行为不稳定。


Notes: 笔记:

  1. In C++ you can't have two pointers of unrelated types pointing to the same object; 在C ++中,不能有两个不相关类型的指针指向同一对象。 this restriction is mostly used to help optimizers with assumptions about aliasing. 此限制主要用于帮助优化器进行有关别名的假设。
  2. Notice that the requirements for this are quite stringent; 请注意,此要求非常严格。 typically most classes that aren't basically C structs don't qualify for this. 通常,大多数基本上不是C结构的类都不符合此条件。 Even having different access qualifiers can break the magic. 即使具有不同的访问限定符也可以打破魔术。
  3. The idea is that assigning to ph makes it the "active object" of the union , and then p.Print() is the one "inspecting" the "inactive" object. 这个想法是,分配给ph使其成为的“活动对象” union ,然后p.Print()是“检查”所述“不活动”对象中的一个。

Yes, the posted code invokes undefined behavior. 是的,发布的代码会调用未定义的行为。 Don't do that. 不要那样做

If you want to see a really insane way that some people accomplish this unsavory goal, here you go: access private member using template trick 如果您想以某种疯狂的方式实现某些人完成这个不愉快的目标的方法,请执行以下操作: 使用模板技巧访问私有成员

But really, don't do that. 但实际上,不要那样做。

PS: never use C-style casts in C++. PS:切勿在C ++中使用C样式的强制转换。 Use static_cast, dynamic_cast, reinterpret_cast, and const_cast, as appropriate. 根据需要使用static_cast,dynamic_cast,reinterpret_cast和const_cast。 C-style casts are needlessly unsafe. C样式的强制转换不必要地是不安全的。

i found the problem 我发现了问题

/*code:*/
#include <stdio.h>

void check(short *h,long *k)
{
    *h=5;
    *k=6;
    if (*h == 5)
        printf("strict aliasing problem\n");
}

int main(void)
{
    long      k[1];
    check((short *)k,k);
    return 0;
}
/*
$ gcc -Wall -ansi -pedantic -O0 -o o0 asd.c
$ ./o0
/output: nothing/
$ gcc -Wall -ansi -pedantic -O2 -o o2 asd.c
$ ./o2
/output: strict aliasing problem/
*/

(same as in c++) (与c ++中相同)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM