31.3 封装
封装是一个把数据装在类的private域里面的动作,这样会让它们只能从类的内部被访问到,而从外面访问不到。 但是,生成的代码里面是否有什么东西指示一个变量是private呢? 没有,让我们看看简单的例子:
#include <stdio.h>
class box
{
private:
int color, width, height, depth;
public:
box(int color, int width, int height, int depth)
{
this->color=color;
this->width=width;
this->height=height;
this->depth=depth;
};
void dump()
{
printf ("this is box. color=%d, width=%d, height=%d, depth=%d
", color, width,
height, depth);
};
};
在MSVC 2008+/Ox和/Ob0选项,然后看看box::dump()代码:
?dump@box@@QAEXXZ PROC ; box::dump, COMDAT
; _this$ = ecx
mov eax, DWORD PTR [ecx+12]
mov edx, DWORD PTR [ecx+8]
push eax
mov eax, DWORD PTR [ecx+4]
mov ecx, DWORD PTR [ecx]
push edx
push eax
push ecx
; ’this is box. color=%d, width=%d, height=%d, depth=%d’, 0aH, 00H
push OFFSET ??_C@_0DG@NCNGAADL@this?5is?5box?4?5color?$DN?$CFd?0?5width?$DN?$CFd?0@
call _printf
add esp, 20 ; 00000014H
ret 0
?dump@box@@QAEXXZ ENDP ; box::dump
这就是类的内存分布:
所有域都不允许其他类的访问,但是,我们知道这个存放方式之后是否可以修改这些域? 所以我加了hack_oop_encapsulation()函数,假设他有这个代码,当然我们没有编译:
void hack_oop_encapsulation(class box * o)
{
o->width=1; // that code can’t be compiled: "error C2248: ’box::width’ : cannot access
private member declared in class ’box’"
};
还有,如果要转换box的类型,把它从指针转为int数组,然后如果我们能修改这些数字,那么我们就成功了。
void hack_oop_encapsulation(class box * o)
{
unsigned int *ptr_to_object=reinterpret_cast<unsigned int*>(o);
ptr_to_object[1]=123;
};
这个函数的代码非常简单,剋说函数指示把指针指向这些int,然后把123写入第二个int:
?hack_oop_encapsulation@@YAXPAVbox@@@Z PROC ; hack_oop_encapsulation
mov eax, DWORD PTR _o$[esp-4]
mov DWORD PTR [eax+4], 123 ; 0000007bH
ret 0
?hack_oop_encapsulation@@YAXPAVbox@@@Z ENDP ; hack_oop_encapsulation
看看它是怎么工作的:
int main()
{
box b(1, 10, 20, 30);
b.dump();
hack_oop_encapsulation(&b);
b.dump();
return 0;
};
运行后:
this is box. color=1, width=10, height=20, depth=30
this is box. color=1, width=123, height=20, depth=30
可以看到,private只是在编译阶段被保护了,c++编译器不会允许其他代码修改private域下的内容,但是如果用一些技巧,就可以修改private的值。
当前内容版权归 beginners.re 或其关联方所有,如需对内容或内容相关联开源项目进行关注与资助,请访问 beginners.re .