程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> c++ 對象的內存布局

c++ 對象的內存布局

編輯:C++入門知識

c++ 對象的內存布局


對象的影響因素   簡而言之,一個類可能會有如下的影響因素: 1)成員變量 2)虛函數(產生虛函數表) 3)單一繼承(只繼承於一個類) 4)多重繼承(繼承多個類) 5)重復繼承(繼承的多個父類中其父類有相同的超類) 6)虛擬繼承(使用virtual方式繼承,為了保證繼承後父類的內存布局只會存在一份) 上述的東西通常是C++這門語言在語義方面對對象內部的影響因素,當然,還會有編譯器的影響(比如優化),還有字節對齊的影響。在這裡我們都不討論,我們只討論C++語言上的影響。   本篇文章著重討論下述幾個情況下的C++對象的內存布局情況。   1)單一的一般繼承(帶成員變量、虛函數、虛函數覆蓋) 2)單一的虛擬繼承(帶成員變量、虛函數、虛函數覆蓋) 3)多重繼承(帶成員變量、虛函數、虛函數覆蓋) 4)重復多重繼承(帶成員變量、虛函數、虛函數覆蓋) 5)鑽石型的虛擬多重繼承(帶成員變量、虛函數、虛函數覆蓋)   (1)單一的一般繼承 下面,我們假設有如下所示的一個繼承關系:       請注意,在這個繼承關系中,父類,子類,孫子類都有自己的一個成員變量。而了類覆蓋了父類的f()方法,孫子類覆蓋了子類的g_child()及其超類的f()。       可見以下幾個方面: 1)虛函數表在最前面的位置。 2)成員變量根據其繼承和聲明順序依次放在後面。 3)在單一的繼承中,被override的虛函數在虛函數表中得到了更新。(Child的f覆蓋Parent的f函數,然後GrandChild的f覆蓋Child的f;GrandChild的g_child覆蓋Child的g_child)    代碼驗證如下       /* version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/29 */   #include "stdafx.h" #include <iostream> using namespace std;   class Parent { public:     int iparent;     Parent (): iparent (10) {}     virtual void f()     {         cout << " Parent::f()" << endl;     }     virtual void g()     {         cout << " Parent::g()" << endl;     }     virtual void h()     {         cout << " Parent::h()" << endl;     }   };   class Child : public Parent { public:     int ichild;     Child(): ichild(100) {}     virtual void f()     {         cout << "Child::f()" << endl;     }     virtual void g_child()     {         cout << "Child::g_child()" << endl;     }     virtual void h_child()     {         cout << "Child::h_child()" << endl;     } };   class GrandChild : public Child { public:     int igrandchild;     GrandChild(): igrandchild(1000) {}     virtual void f()     {         cout << "GrandChild::f()" << endl;     }     virtual void g_child()     {         cout << "GrandChild::g_child()" << endl;     }     virtual void h_grandchild()     {         cout << "GrandChild::h_grandchild()" << endl;     } };   typedef void(*Fun)(void);   /* vptr       ---> Parent::f(),Parent::g(),Parent::h() iparent */ void test_parent() {     Parent obj;     Fun pFun;     int **pVtab = (int **)(&obj);       int n = 3;     cout << "[0] Parent::_vptr->" << endl;     for (int i = 0; i < n; i++)     {         pFun = (Fun)pVtab[0][i];         cout << "------[" << i << "] ";         pFun();     }     cout << "[1] Parent.iparent = " << (int)pVtab[1] << endl;     cout << "============================================" << endl; }   /* vptr       ---> Child::f(),Parent::g(),Parent::h(),Child::g_child(),Child::h_child() iparent ichild */ void test_child() {     Child obj;     Fun pFun;     int **pVtab = (int **)(&obj);       int n = 5;     cout << "[0] Child::_vptr->" << endl;     for (int i = 0; i < n; i++)     {         pFun = (Fun)pVtab[0][i];         cout << "------[" << i << "] ";         pFun();     }     cout << "[1] Parent.iparent = " << (int)pVtab[1] << endl;     cout << "[2] Child.ichild = " << (int)pVtab[2] << endl;     //cout << "[3] GrandChild.igrandchild = " << (int)pVtab[3] << endl;     cout << "============================================" << endl; }     /* vptr       ---> GrandChild::f(),Parent::g(),Parent::h(),GrandChild::g_child(),Child::h_child() iparent ichild igrandchild */ void test_grandchild() {     GrandChild obj;     Fun pFun;     int **pVtab = (int **)(&obj);       int n = 5;     cout << "[0] GrandChild::_vptr->" << endl;     for (int i = 0; i < n; i++)     {         pFun = (Fun)pVtab[0][i];         cout << "------[" << i << "] ";         pFun();     }     cout << "[1] Parent.iparent = " << (int)pVtab[1] << endl;     cout << "[2] Child.ichild = " << (int)pVtab[2] << endl;     cout << "[3] GrandChild.igrandchild = " << (int)pVtab[3] << endl;     cout << "============================================" << endl; }   int main() {     test_parent();     test_child();     test_grandchild();     return 0; } /* [0] Parent::_vptr-> ------[0]  Parent::f() ------[1]  Parent::g() ------[2]  Parent::h() [1] Parent.iparent = 10 ============================================ [0] Child::_vptr-> ------[0] Child::f() ------[1]  Parent::g() ------[2]  Parent::h() ------[3] Child::g_child() ------[4] Child::h_child() [1] Parent.iparent = 10 [2] Child.ichild = 100 ============================================ [0] GrandChild::_vptr-> ------[0] GrandChild::f() ------[1]  Parent::g() ------[2]  Parent::h() ------[3] GrandChild::g_child() ------[4] Child::h_child() [1] Parent.iparent = 10 [2] Child.ichild = 100 [3] GrandChild.igrandchild = 1000 ============================================ */ (2)多重繼承 下面,再讓我們來看看多重繼承中的情況,假設有下面這樣一個類的繼承關系。注意:子類只overwrite了父類的f()函數,而還有一個是自己的函數(我們這樣做的目的是為了用g1()作為一個標記來標明子類的虛函數表)。而且每個類中都有一個自己的成員變量:       我們的類繼承的源代碼如下所示:父類的成員初始為10,20,30,子類的為100   使用圖片表示是下面這個樣子:       我們可以看到: 1) 每個父類都有自己的虛表。 2) 子類的成員函數被放到了第一個父類的表中。 3) 內存布局中,其父類布局依次按聲明順序排列。 4) 每個父類的虛表中的f()函數都被override成了子類的f()。這樣做就是為了解決不同的父類類型的指針指向同一個子類實例,而能夠調用到實際的函數。   代碼驗證如下     /* version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/29 */   #include "stdafx.h" #include <iostream> using namespace std;     class Base1 { public:     int ibase1;     Base1(): ibase1(10) {}     virtual void f()     {         cout << "Base1::f()" << endl;     }     virtual void g()     {         cout << "Base1::g()" << endl;     }     virtual void h()     {         cout << "Base1::h()" << endl;     }   };   class Base2 { public:     int ibase2;     Base2(): ibase2(20) {}     virtual void f()     {         cout << "Base2::f()" << endl;     }     virtual void g()     {         cout << "Base2::g()" << endl;     }     virtual void h()     {         cout << "Base2::h()" << endl;     } };   class Base3 { public:     int ibase3;     Base3(): ibase3(30) {}     virtual void f()     {         cout << "Base3::f()" << endl;     }     virtual void g()     {         cout << "Base3::g()" << endl;     }     virtual void h()     {         cout << "Base3::h()" << endl;     } };     class Derive : public Base1, public Base2, public Base3 { public:     int iderive;     Derive(): iderive(100) {}     virtual void f()     {         cout << "Derive::f()" << endl;     }     virtual void g1()     {         cout << "Derive::g1()" << endl;     } };   typedef void(*Fun)(void);   /* Base1 vptr---> Derive::f(),Base1::g(),Base1::h(),Derive::g1() ibase1 Base2 vptr--->Derive::f(),Base2::g(),Base2::h() ibase2 Base3 vptr--->Derive::f(),Base3::g(),Base3::h() ibase3 iderive */ void test() {     Derive obj;     Fun pFun;     int **pVtab = (int **)(&obj);       int n = 4;     cout << "[0] Base1::_vptr->" << endl;     for (int i = 0; i < n; i++)     {         pFun = (Fun)pVtab[0][i];         cout << "------[" << i << "] ";         pFun();     }     cout << "[1] Base1.ibase1 = " << (int)pVtab[1] << endl;     cout << "============================================" << endl;     n = 3;     cout << "[2] Base2::_vptr->" << endl;     for (int i = 0; i < n; i++)     {         pFun = (Fun)pVtab[2][i];         cout << "------[" << i << "] ";         pFun();     }     cout << "[3] Base2.ibase2 = " << (int)pVtab[3] << endl;     cout << "============================================" << endl;     n = 3;     cout << "[4] Base3::_vptr->" << endl;     for (int i = 0; i < n; i++)     {         pFun = (Fun)pVtab[4][i];         cout << "------[" << i << "] ";         pFun();     }     cout << "[5] Base3.ibase3 = " << (int)pVtab[5] << endl;     cout << "============================================" << endl;     cout << "[6] Derive.iderive = " << (int)pVtab[6] << endl; }   int main() {     test();     return 0; } /* [0] Base1::_vptr-> ------[0] Derive::f() ------[1] Base1::g() ------[2] Base1::h() ------[3] Derive::g1() [1] Base1.ibase1 = 10 ============================================ [2] Base2::_vptr-> ------[0] Derive::f() ------[1] Base2::g() ------[2] Base2::h() [3] Base2.ibase2 = 20 ============================================ [4] Base3::_vptr-> ------[0] Derive::f() ------[1] Base3::g() ------[2] Base3::h() [5] Base3.ibase3 = 30 ============================================ [6] Derive.iderive = 100 */  (3)重復繼承 下面我們再來看看,發生重復繼承的情況。所謂重復繼承,也就是某個基類被間接地重復繼承了多次。 下圖是一個繼承圖,我們重載了父類的f()函數。       下面是對於子類實例中的虛函數表的圖:       我們可以看見,最頂端的父類B其成員變量存在於B1和B2中,並被D給繼承下去了。而在D中,其有B1和B2的實例,於是B的成員在D的實例中存在兩份,一份是B1繼承而來的,另一份是B2繼承而來的。所以,如果我們使用以下語句,則會產生二義性編譯錯誤:       void test_error() {     D d;     // d.ib = 1;    //ERROR     d.B1::ib = 1;   // ok     d.B2::ib = 100; // ok } 注意,上面例程中的最後兩條語句存取的是兩個變量。雖然我們消除了二義性的編譯錯誤,但B類在D中還是有兩個實例,這種繼承造成了數據的重復,我們叫這種繼承為重復繼承。重復的基類數據成員可能並不是我們想要的。所以,C++引入了虛基類的概念。    代碼驗證如下       /* version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/29 */   #include "stdafx.h" #include <iostream> using namespace std;     class B { public:     int ib;     char cb; public:     B(): ib(0), cb('B') {}       virtual void f()     {         cout << "B::f()" << endl;     }     virtual void Bf()     {         cout << "B::Bf()" << endl;     } };   class B1 :  public B { public:     int ib1;     char cb1; public:     B1(): ib1(11), cb1('1') {}       virtual void f()     {         cout << "B1::f()" << endl;     }     virtual void f1()     {         cout << "B1::f1()" << endl;     }     virtual void Bf1()     {         cout << "B1::Bf1()" << endl;     }   };   class B2:  public B { public:     int ib2;     char cb2; public:     B2(): ib2(12), cb2('2') {}       virtual void f()     {         cout << "B2::f()" << endl;     }     virtual void f2()     {         cout << "B2::f2()" << endl;     }     virtual void Bf2()     {         cout << "B2::Bf2()" << endl;     }   };   class D : public B1, public B2 { public:     int id;     char cd; public:     D(): id(100), cd('D') {}       virtual void f()     {         cout << "D::f()" << endl;     }     virtual void f1()     {         cout << "D::f1()" << endl;     }     virtual void f2()     {         cout << "D::f2()" << endl;     }     virtual void Df()     {         cout << "D::Df()" << endl;     }   };   typedef void(*Fun)(void);     void test_error() {     D d;     // d.ib = 1;    //ERROR     d.B1::ib = 1;   // ok     d.B2::ib = 100; // ok }   /* B1.vptr --->D::f,B::Bf,D::f1,B1::Bf1,D::Df B.ib B.cb B1.ib1 B1.cb1   B2.vptr --->D::f,B::Bf,D::f2,B2::Bf2 B.ib B.cb B2.ib2 B2.cb2   D.id D.cd */ void test_public() {     D obj;     Fun pFun;     int **pVtab = (int **)(&obj);       int n = 5;     cout << "[0] D::B1::_vptr->" << endl;     for (int i = 0; i < n; i++)     {         pFun = (Fun)pVtab[0][i];         cout << "------[" << i << "] ";         pFun();     }     cout << "[1] B.ib = " << (int)pVtab[1] << endl;     cout << "[2] B.cb = " << (char)pVtab[2] << endl;     cout << "[3] B1.ib1 = " << (int)pVtab[3] << endl;     cout << "[4] B1.cb1 = " << (char)pVtab[4] << endl;       n = 4;     cout << "[5] D::B2::_vptr->" << endl;     for (int i = 0; i < n; i++)     {         pFun = (Fun)pVtab[5][i];         cout << "------[" << i << "] ";         pFun();     }     cout << "[6] B.ib = " << (int)pVtab[6] << endl;     cout << "[7] B.cb = " << (char)pVtab[7] << endl;     cout << "[8] B2.ib2 = " << (int)pVtab[8] << endl;     cout << "[9] B2.cb2 = " << (char)pVtab[9] << endl;       cout << "[10] D.id = " << (int)pVtab[10] << endl;     cout << "[11] D.cd = " << (char)pVtab[11] << endl; }   void test_virtual_public() {   }   int main() {     test_public();     return 0; } /* [0] D::B1::_vptr-> ------[0] D::f() ------[1] B::Bf() ------[2] D::f1() ------[3] B1::Bf1() ------[4] D::Df() [1] B.ib = 0 [2] B.cb = B [3] B1.ib1 = 11 [4] B1.cb1 = 1 [5] D::B2::_vptr-> ------[0] D::f() ------[1] B::Bf() ------[2] D::f2() ------[3] B2::Bf2() [6] B.ib = 0 [7] B.cb = B [8] B2.ib2 = 12 [9] B2.cb2 = 2 [10] D.id = 100 [11] D.cd = D */

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved