你私藏了不少好东西(private
member),除了friend,不拿出来给别人共享。但是我现在已经知道你有这个东西,而且知道它在你家(class或者struct)的什么位置。
我就派了个窃贼(pointer),通过一条秘道(memory access)把这些东西占为己有。
简单一点,如果你只是一个收藏家(只有成员变量和公共构造函数),而且你家的地图是这样子的(一看就知道是小家子):
struct home{
home(){
TV = 111;
CD = 222;
}
private :
int TV, CD;
};
先侦察一下地形:
cout << sizeof(home) << endl;
结果是8,就是两个int的大小,因为静态函数是不占类空间的。先摸到你家门口吧,获取一个类指针。
home *h = new home();
好,我找来一个窃贼:
typedef unsigned char byte_t;
byte_t *ptr = 0;
其实在这个例子中可以用int类型的指针,但用字节类型的更具有通用性(c++是没有字节类型的,只有自己定义);
ptr = (byte_t*)h;
现在已经成功潜入!
一个类的内存分布是按照成员列表的顺序安排的。
现在我不想要电视机(h->TV),我只想要Ayaka签名cd(h->CD);
ptr += 4;//跳过h->TV的内存空间。
现在已经获得了h->CD的内存初始位置,再进行一次强制转换:
int *val = 0;
val = (int*)ptr;
cout << val << endl;
打印出222,窃取成功!
如果类经过了继承,要注意,子类的内存分布是这样的:先排列父类的成员,再排列自己的成员,多重继承以此类推。
如果类中或者父类中有虚函数,那么要注意类里面有一个虚指针的开销,一般都是在类的头部,比如说:
struct A{
int v1;
A(){
v1 = 444;
}
virtual void pt(){
v1 = 10;
cout << v1 << endl;
}
};
struct B : public A{
private :
string str;
int v2, v3;
public :
B(){
v1 = 333;
str = "hello";
v2 = 100;
v3 = 200;
}
};
sizeof(A)是8,sizeof(B)是20,sizeof(string)是4。
这时候:
B *b = new B();
byte_t *ptr = 0;
ptr = (byte_t*)b;
ptr += 4;//略过虚指针
此时指向的是父类的成员v1,提醒一下,构造的顺序是从父到子,和析构相反。所以这个case里面v1的值是333而不是444。
ptr += 4;
此时指向的是子类的string类型的str。
同样可以把数据窃取出来。
阅读(1300) | 评论(0) | 转发(1) |