31.4 多重继承

多重继承是一个类的创建,这个类会从2个或多个类里面继承函数和成员。 看一个简单的例子:

  1. #include <stdio.h>
  2. class box
  3. {
  4. public:
  5. int width, height, depth;
  6. box() { };
  7. box(int width, int height, int depth)
  8. {
  9. this->width=width;
  10. this->height=height;
  11. this->depth=depth;
  12. };
  13. void dump()
  14. {
  15. printf ("this is box. width=%d, height=%d, depth=%d", width, height, depth);
  16. };
  17. int get_volume()
  18. {
  19. return width * height * depth;
  20. };
  21. };
  22. class solid_object
  23. {
  24. public:
  25. int density;
  26. solid_object() { };
  27. solid_object(int density)
  28. {
  29. this->density=density;
  30. };
  31. int get_density()
  32. {
  33. return density;
  34. };
  35. void dump()
  36. {
  37. printf ("this is solid_object. density=%d", density);
  38. };
  39. };
  40. class solid_box: box, solid_object
  41. {
  42. public:
  43. solid_box (int width, int height, int depth, int density)
  44. {
  45. this->width=width;
  46. this->height=height;
  47. this->depth=depth;
  48. this->density=density;
  49. };
  50. void dump()
  51. {
  52. printf ("this is solid_box. width=%d, height=%d, depth=%d, density=%d", width, height, depth, density);
  53. };
  54. int get_weight() { return get_volume() * get_density(); };
  55. };
  56. int main()
  57. {
  58. box b(10, 20, 30);
  59. solid_object so(100);
  60. solid_box sb(10, 20, 30, 3);
  61. b.dump();
  62. so.dump();
  63. sb.dump();
  64. printf ("%d", sb.get_weight());
  65. return 0;
  66. };

让我们在MSVC 2008中用/Ox和/Ob0选项来编译,然后看看box::dump()、solid_object::dump()和solid_box::dump()的函数代码:

  1. ?dump@box@@QAEXXZ PROC ; box::dump, COMDAT
  2. ; _this$ = ecx
  3. mov eax, DWORD PTR [ecx+8]
  4. mov edx, DWORD PTR [ecx+4]
  5. push eax
  6. mov eax, DWORD PTR [ecx]
  7. push edx
  8. push eax
  9. ; this is box. width=%d, height=%d, depth=%d’, 0aH, 00H
  10. push OFFSET ??_C@_0CM@DIKPHDFI@this?5is?5box?4?5width?$DN?$CFd?0?5height?$DN?$CFd@
  11. call _printf
  12. add esp, 16 ; 00000010H
  13. ret 0
  14. ?dump@box@@QAEXXZ ENDP ; box::dump
  15. ?dump@solid_object@@QAEXXZ PROC ; solid_object::dump, COMDAT
  16. ; _this$ = ecx
  17. mov eax, DWORD PTR [ecx]
  18. push eax
  19. ; this is solid_object. density=%d’, 0aH
  20. push OFFSET ??_C@_0CC@KICFJINL@this?5is?5solid_object?4?5density?$DN?$CFd@
  21. call _printf
  22. add esp, 8
  23. ret 0
  24. ?dump@solid_object@@QAEXXZ ENDP ; solid_object::dump
  25. ?dump@solid_box@@QAEXXZ PROC ; solid_box::dump, COMDAT
  26. ; _this$ = ecx
  27. mov eax, DWORD PTR [ecx+12]
  28. mov edx, DWORD PTR [ecx+8]
  29. push eax
  30. mov eax, DWORD PTR [ecx+4]
  31. mov ecx, DWORD PTR [ecx]
  32. push edx
  33. push eax
  34. push ecx
  35. ; this is solid_box. width=%d, height=%d, depth=%d, density=%d’, 0aH
  36. push OFFSET ??_C@_0DO@HNCNIHNN@this?5is?5solid_box?4?5width?$DN?$CFd?0?5hei@
  37. call _printf
  38. add esp, 20 ; 00000014H
  39. ret 0
  40. ?dump@solid_box@@QAEXXZ ENDP ; solid_box::dump

所以,这三个类的内存分布是:

Box:

31.4 多重继承 - 图1

Solid_object:

31.4 多重继承 - 图2

可以说,solid_box的类内存空间就是它们的组合:

31.4 多重继承 - 图3

Box::get_volume()和solid_object::get_density()函数的代码如下:

  1. ?get_volume@box@@QAEHXZ PROC ; box::get_volume, COMDAT
  2. ; _this$ = ecx
  3. mov eax, DWORD PTR [ecx+8]
  4. imul eax, DWORD PTR [ecx+4]
  5. imul eax, DWORD PTR [ecx]
  6. ret 0
  7. ?get_volume@box@@QAEHXZ ENDP ; box::get_volume
  8. ?get_density@solid_object@@QAEHXZ PROC ; solid_object::get_density, COMDAT
  9. ; _this$ = ecx
  10. mov eax, DWORD PTR [ecx]
  11. ret 0
  12. ?get_density@solid_object@@QAEHXZ ENDP ; solid_object::get_density

但是solid_box::get_weight()的代码更有趣:

  1. ?get_weight@solid_box@@QAEHXZ PROC ; solid_box::get_weight, COMDAT
  2. ; _this$ = ecx
  3. push esi
  4. mov esi, ecx
  5. push edi
  6. lea ecx, DWORD PTR [esi+12]
  7. call ?get_density@solid_object@@QAEHXZ ; solid_object::get_density
  8. mov ecx, esi
  9. mov edi, eax
  10. call ?get_volume@box@@QAEHXZ ; box::get_volume
  11. imul eax, edi
  12. pop edi
  13. pop esi
  14. ret 0
  15. ?get_weight@solid_box@@QAEHXZ ENDP ; solid_box::get_weight

Get_weight()函数只会调用2个函数,但是对于get_volume()来说,他只是传递指针给this,对get_density()来说,他指示传递指针给this,同时移位12(0xC)字节,然后在solid_box类的内存空间理,solid_object类开始了。 因此,solid_object::get_density()方法相信它正在处理普通的solid_object类,而且box::get_volume类将对它的3个域生效,而且相信这是普通的box类对象。 因此,我们可以说,类的一个对象,是从多个其他类继承阿日来,在内存中代表着组合起来的类,因为它有所有继承来的域。每个继承的方法都会又一个指向对应结构部分的指针来处理。