C++ 虛函數和多重繼承的內存佈局初探

C++ 對象的內存佈局

一切以事實說話:html

代碼:app

   1: #include <stdio.h> 
   2:  
   3: class A {
   4:   public:   
   5:     int a;
   6:     int b;  
   7:     int c;  
   8: };
   9:  
  10: int main(int argc, char** argv) {
  11:   A obj;
  12:   printf(" obj   :%p\n obj.a: %p \n obj.b: %p \n obj.c: %p\n" ,                                                          
  13:         &obj, &obj.a, &obj.b, &obj.c);
  14:   return 0;
  15: }

執行結果:函數

image

不一樣的機器執行的結果可能不一樣,可是從這裏的出的一個結論是:佈局

對象的地址是整個類的起始地址(也就是低地址)。其成員的地址順序和其在類中聲明的順序有關係。測試

而對上面的代碼稍加修改,增長一個虛函數。ui

   1: #include <stdio.h>
   2:  
   3: class A { 
   4:   public:
   5:     virtual void show() {}                                                                                               
   6:     int a;
   7:     int b;
   8:     int c;
   9: };
  10:  
  11: int main(int argc, char** argv) {
  12:   A obj;
  13:   printf(" obj   :%p\n obj.a: %p \n obj.b: %p \n obj.c: %p\n" ,
  14:         &obj, &obj.a, &obj.b, &obj.c);
  15:   return 0;
  16: }

測試結果:spa

image

這裏是因爲增長了一個虛函數表的指針(測試機器爲64位系統,故指針爲8個字節)。從這裏能夠看出,虛函數表指針在類的起始地址,這也是爲了對於不一樣的類該地址的偏移相同。.net

   1: class X {
   2: };
   3: class Y {
   4:   public:
   5:     virtual void f() {};
   6: };
   7: class X1 : public virtual X {
   8: };
   9: class X2 : public virtual X {
  10: };
  11: class A1 : public X1, public X2 {
  12: };
  13: class X3 : public X {
  14: };
  15: class X4 : public X {
  16: };
  17: class A2 : public X3, public X4 {
  18: };
  19: class Y1 : public virtual Y {
  20: };
  21: class Y2 : public virtual Y {
  22: };
  23: class B1 : public Y1, public Y2 {
  24: };
  25: class Y3 : public Y {
  26: };
  27: class Y4 : public Y {
  28: };
  29: class B2 : public Y3, public Y4 {
  30: };
  31:  
  32: int main (int argc, char** argv) {
  33:   printf("sizeof(X) %lu\n", sizeof(X));
  34:   printf("sizeof(Y) %lu\n", sizeof(Y));
  35:   printf("sizeof(X1) %lu\n", sizeof(X1));
  36:   printf("sizeof(X2) %lu\n", sizeof(X2));
  37:   printf("sizeof(A1) %lu\n", sizeof(A1));
  38:   printf("sizeof(X3) %lu\n", sizeof(X3));
  39:   printf("sizeof(X4) %lu\n", sizeof(X4));
  40:   printf("sizeof(A2) %lu\n", sizeof(A2));
  41:   printf("sizeof(Y1) %lu\n", sizeof(Y1));
  42:   printf("sizeof(Y2) %lu\n", sizeof(Y2));
  43:   printf("sizeof(B1) %lu\n", sizeof(B1));
  44:   printf("sizeof(Y3) %lu\n", sizeof(Y3));
  45:   printf("sizeof(Y4) %lu\n", sizeof(Y4));
  46:   printf("sizeof(B2) %lu\n", sizeof(B2));
  47:   return 0;
  48: }        

執行結果:unix

image

上面的測試結果得出的結論:指針

  1. 空類的大小不是0,而是1,這樣是提供一個佔位符,這樣由空類建立出的兩個對象的地址就會不一樣,以做區分。
  2. 當類不是空的時候,該佔位符就不須要了,類的大小就是類中成員所需的空間大小

注: 本想深刻一探究竟,不過這部分和編譯器有很大的關係,非朝夕能夠搞定。先寫這麼多,再多作了解後再補充吧。

refer:

http://blog.csdn.net/haoel/article/details/3081328

http://blog.csdn.net/haoel/article/details/3081385

http://blog.chinaunix.net/uid-22535463-id-2749544.html

相關文章
相關標籤/搜索