C++對象模型的一點理解

 這兩天一直在研究對象模型的問題,發現這個問題確實不好理解,但通過反彙編,對於彙編下,數據段,代碼段有了一定的認識。
經過兩天的研究測試發現當一個類被定義了之後,數據和函數是分離的,函數是放在斷碼段的,函數名標示函數的起始地址,往下就是函數內部的指令
當創建一個類的object時,棧上開闢空間來容納其中的數據變量,然後調用構造函數來初始化數據成員,如何調用構造函數我至今也不太清楚。。。

#include <iostream>
using namespace std;
class A
{
    public:
    A()
    {
        cout << "A's constructor" << endl;
    }//標記3
    A(int i):a(i){}
    A(const A &orig):a(orig.a)
    {

    }
    A& operator = (const A &orig)
    {
        a = orig.a;
        return *this;
    }
    virtual ~A(){}
    private:
    int a;
};
class B:publicA
{
    public:
    B()
    {
        cout << "B's constructor" << endl;
    }//標記2
    B(int i,int x):A(i),b(x){}
    B(const B &orig):A(orig),b(orig.b)
    {

    }
    B& operator = (const B &orig)
    {
        A::operator = (orig);
        b = orig.b;
        return *this;
    }
    ~B(){}
    private:
    int b;
};
int main()
{
    A *p = new B;//
    return 0;
}


對於上面這段代碼通過反彙編發現
0041C94C A()
0041C9D4 ~A()
0041C9FC B()
0041CAEC ~B()
說明代碼段中,基類成員函數的位置處於上層,派生類在下層,這和C++繼承體系裏的scope吻合不是巧然,這說明編譯器在查找函數的時候是由下層地址往上層地址去找的。
B類對象模型如下:

------ <<--- this      --------                ----------
|vpt | ------>>       | ~B地址 | <<-----虛表     | A      | <<-----代碼段
------                 --------                 ~A
|a   |                                         | ...    |
------                                           B   
|b   |                                         | ~B     |
------                                         ----------


上圖是我推測的B類對象的模型,首先創建對象的時候棧上分配一段空間裝數據成員,因爲有虛函數所以附帶一個vpt,指向虛函數表的首地址,這個是B類的虛函數表,這裏只有一個虛析構函數,在B類的虛函數表裏把A的虛析構函數替換了。
分配空間之後,調用構造函數來初始化變量,這個時候就跳到代碼段B()的位置,然後又向上層地址找到A()的位置,執行裏面的指令(給a賦值),然後回到B(),執行裏面的指令(給b賦值)
析構的時候,這裏析構函數是虛的,然後就根據確切類型,也就是B類,去B類的虛表中找,結果找到了~B(),然後跳到代碼段~B()執行完裏面的指令在向上層地址找到~A()
如果A的析構函數不是虛的,那麼對象模型就完全不同

------ <<--- this     --------   
|a   |                | A    | <<-----代碼段   
------                  ~A   
|b   |                | ...  |   
------                  B   
                      | ~B   |
                      --------


這裏就沒有所謂的虛表了,析構的時候,虛函數不是虛的,調用就不是通過虛表了,這個時候根據靜態綁定,這個時候就直接跳到了代碼段~A(),然後執行裏面的指令,這個時候編譯器再不會去找~B()了,因爲它在下層地址,結果造成了所謂的內存泄漏  
這些就是我的理解了,就當拋磚引玉吧...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章