此代码是否导致未定义的行为?或者我可以遇到这个问题? (复制没有函数的完整类,只使用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;
}
输出:
(4, 5)
(1, 2)
(当然是原始会员订单)
答案 0 :(得分:3)
尽管您的类与布局兼容(请参阅下文),但由于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;
}
这是因为Point
和PointHack
是标准布局类 2 (C ++ 11,§9¶7),并且共享一个“共同点”初始子序列“(§9.2,¶20);因此,如果它们都存储在同一个联合中(这里pu
),则允许“检查它们中任何一个的共同初始部分” 3 。
不过,这个答案主要是一种风格的练习;除非你真的被迫,否则不要利用这些技巧。如果有必要,C ++提供更好的方法来访问私有成员而不会破坏封装 - 你有getter / setter,受保护的继承,朋友类,......一般来说,如果你以你的目标类不想要的方式访问私有类成员,您可能违反了该类关于其数据如何被修改的假设,这可能导致其方法代码的不稳定行为。
注意:
ph
会使其成为union
的“活动对象”,然后p.Print()
就是“检查”“非活动”对象。答案 1 :(得分:1)
是的,发布的代码会调用未定义的行为。不要那样做。
如果你想看到某些人实现这个令人讨厌的目标的疯狂方式,请转到:access private member using template trick
但实际上,不要这样做。
P.S。:从不在C ++中使用C风格的演员表。根据需要使用static_cast,dynamic_cast,reinterpret_cast和const_cast。 C风格的演员阵容不必要地不安全。
答案 2 :(得分:0)
我发现了问题
/*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/
*/
(与c ++相同)