31.3 封装

封装是一个把数据装在类的private域里面的动作,这样会让它们只能从类的内部被访问到,而从外面访问不到。 但是,生成的代码里面是否有什么东西指示一个变量是private呢? 没有,让我们看看简单的例子:

  1. #include <stdio.h>
  2. class box
  3. {
  4. private:
  5. int color, width, height, depth;
  6. public:
  7. box(int color, int width, int height, int depth)
  8. {
  9. this->color=color;
  10. this->width=width;
  11. this->height=height;
  12. this->depth=depth;
  13. };
  14. void dump()
  15. {
  16. printf ("this is box. color=%d, width=%d, height=%d, depth=%d
  17. ", color, width,
  18. height, depth);
  19. };
  20. };

在MSVC 2008+/Ox和/Ob0选项,然后看看box::dump()代码:

  1. ?dump@box@@QAEXXZ PROC ; box::dump, COMDAT
  2. ; _this$ = ecx
  3. mov eax, DWORD PTR [ecx+12]
  4. mov edx, DWORD PTR [ecx+8]
  5. push eax
  6. mov eax, DWORD PTR [ecx+4]
  7. mov ecx, DWORD PTR [ecx]
  8. push edx
  9. push eax
  10. push ecx
  11. ; this is box. color=%d, width=%d, height=%d, depth=%d’, 0aH, 00H
  12. push OFFSET ??_C@_0DG@NCNGAADL@this?5is?5box?4?5color?$DN?$CFd?0?5width?$DN?$CFd?0@
  13. call _printf
  14. add esp, 20 ; 00000014H
  15. ret 0
  16. ?dump@box@@QAEXXZ ENDP ; box::dump

这就是类的内存分布:

31.3 封装 - 图1

所有域都不允许其他类的访问,但是,我们知道这个存放方式之后是否可以修改这些域? 所以我加了hack_oop_encapsulation()函数,假设他有这个代码,当然我们没有编译:

  1. void hack_oop_encapsulation(class box * o)
  2. {
  3. o->width=1; // that code can’t be compiled: "error C2248: ’box::width’ : cannot access
  4. private member declared in class box"
  5. };

还有,如果要转换box的类型,把它从指针转为int数组,然后如果我们能修改这些数字,那么我们就成功了。

  1. void hack_oop_encapsulation(class box * o)
  2. {
  3. unsigned int *ptr_to_object=reinterpret_cast<unsigned int*>(o);
  4. ptr_to_object[1]=123;
  5. };

这个函数的代码非常简单,剋说函数指示把指针指向这些int,然后把123写入第二个int:

  1. ?hack_oop_encapsulation@@YAXPAVbox@@@Z PROC ; hack_oop_encapsulation
  2. mov eax, DWORD PTR _o$[esp-4]
  3. mov DWORD PTR [eax+4], 123 ; 0000007bH
  4. ret 0
  5. ?hack_oop_encapsulation@@YAXPAVbox@@@Z ENDP ; hack_oop_encapsulation

看看它是怎么工作的:

  1. int main()
  2. {
  3. box b(1, 10, 20, 30);
  4. b.dump();
  5. hack_oop_encapsulation(&b);
  6. b.dump();
  7. return 0;
  8. };

运行后:

  1. this is box. color=1, width=10, height=20, depth=30
  2. this is box. color=1, width=123, height=20, depth=30

可以看到,private只是在编译阶段被保护了,c++编译器不会允许其他代码修改private域下的内容,但是如果用一些技巧,就可以修改private的值。