C++ 類生成對象時內存的結構

一個類中都有什麼元素呢?

成員變量、成員函數。

成員變量又分普通的成員變量、static靜態成員變量、const常量

成員函數分爲普通成員函數、靜態成員函數、虛函數、純虛函數等

那麼他們分別又是如何在類的內存中分配的呢?

 

1.內存對齊原則

不論是在類中還是在結構體中,都需要內存對齊,具體對齊方式(有一個對齊係數——可以自己定義,同常是2、4或4的倍數,不是對齊係數倍數的元素會擴展到對齊係數的倍數上,整體的內存大小也是對齊係數的整數倍)。

2.空類

作爲空類在內存中編譯器會自動爲該類申請一字節的內存空間,方便在代碼區存儲這個類。

3.成員變量在內存中的存儲方式

順序存貯!在內存中,不論類中的普通變量(即存在棧中的變量)是私有類型還是共有類型、保護類型,在內存中的存貯方式都是順序存儲結構,const(常量)類型在內存中依舊是順序結構。但是靜態變量由於要在主函數外部、類外部進行變量的再次空間賦值聲明,導致並沒有存在類裏的同一塊棧空間裏,而是另一塊的棧空間,所以他們之間的內存空間是不連續的。

4.成員函數在內存中的存儲方式

作爲一個類的成員函數,這些成員函數在編譯的時候就已經放到了代碼區,在運行時再分配內存。同一個類的所有對象共享同一段代碼區內存的成員函數,相當於對象只實例化其中變量的地址,並沒有實例化函數,函數是一直存在哪裏的。不論是普通成員函數還是靜態了、常量啦、虛函數啦、純虛函數就不一樣了!在內存中都是鏈式結構存儲的。(也有可能有什麼規律但是在我輸出內存看的時候並沒有發現)

#include <iostream>
#include <cstdio>

using namespace std;

// 可以看到空類編譯時也會分配一個字節內存,隱含添加內存
class A {

};

// 類中的成員變量內存分佈像結構體一樣,有內存對齊,並且是連續分配內存空間的
class B {
public:
    int a;
    int b;
    char c;
};

// 不過其中的char類型成員變量我就沒有看懂了
class C {
public:
    char a; // char 類型成員變量非常的奇怪
};

class D {
public:
    int a;
    int b;
    void func1 () {}
    void func2 () {
        int i;

    }

    virtual void func3 () {
        cout << "virtual" << endl;
    }
};

class ownerShip {
private:
    int a;
    int b;
public:
    int c;
    ownerShip () {
    }

    void coutAddress () {
        cout << "ownerShip a address is : " << &a << endl;
        cout << "ownerShip b address is : " << &b << endl;
        cout << "ownerShip c address is : " << &c << endl;

        // 要注意此處有兩種寫法,一是通過全局的類名字方式訪問成員函數,另一種是通過this指針傳遞過來的類內部
        printf ("ownerShip coutAddress is : %p \n", (void *)&ownerShip::coutAddress);
        printf ("ownerShip coutAddress is : %p \n", (void *)&this->coutAddress);
        printf ("ownerShip func address is : %p \n", (void * ) &this->func);

        printf ("ownerShip func1 address is : %p \n", (void *) &this->func1); // 虛函數
        //printf ("ownerShip func2 address is : %p \n", (void *) &this->func2); // 純虛函數

        printf ("ownerShip func3 address is : %p \n", (void *) &this->func3); // 靜態函數

    }

    // 成員函數有一個指向自己類的指針,意味着成員函數可以通過調用this指針調用這個函數自身

    void func () {
    }

    virtual void func1 () {
        cout << 1 << endl;
    }

    //virtual void func2 () = 0;

    static void func3 () {
        cout << 2 << endl;
    }

    const void func4 () {
        cout << 3 << endl;
    }

    const static func5 () {
        cout << "fuck" << endl;
    }

    static const func6 () {
        cout << "fuck!!" << endl;
    }

};

/*
class sub_for_virtual : public ownerShip{
public:
    void func2 () {
        cout << "sub virtual" << endl;
    }
};
/**/

class verifyVar {
private:
    int a;
    double b;
    static int e;
    static int g;
    const int j = 1;
public:
    float c;
    bool d;
    static int f;
    static int h;
    const int i = 2;

    void func () {
        // 順序結構
        cout << "verify a address is : " << &a << endl;
        cout << "verify b address is : " << &b << endl;
        cout << "verify j address is : " << &j << endl;
        cout << "verify c address is : " << &c << endl;
        //cout << &e << endl;
        //cout << &f << endl;
        cout << "verify d address is : " << &d << endl;
        cout << "verify i address is : " << &i << endl;

        printf ("%p\n", (void*)&this->func);
    }
};

class funcStorage {
public:


    int func () {}

    virtual void func1 () {}

    static func2 () {}

    const func3 () {}

    void cout_ () {
        cout << endl;
        printf ("func is : %p\n", (void*)&this->func);
        printf ("func1 is : %p\n", (void*)&this->func1);
        printf ("func2 is : %p\n", (void*)&this->func2);
        printf ("func3 is : %p\n", (void*)&this->func3);
    }
};

int e = 0;
int f = 1;
int g = 2;
int h = 3;

int main ()
{
    A a;
    cout << sizeof (A) << endl;
    cout << sizeof (a) << endl;

    B b;
    cout << sizeof (B) << endl;
    cout << sizeof (b) << endl;
    cout << "B address : " << &b << endl;
    cout << "B->a address : " << &(b.a) << endl;
    cout << "B->b address : " << &(b.b) << endl;
    cout << "B->c address : " << &(b.c) << endl;

    C c;
    cout << "C address : " << &c << endl;
    cout << "C->a address : " << &(c.a) << endl;

    D d;
    cout << "D size is : " << sizeof (D) << endl;
    cout << "D address is : " << &d << endl;
    cout << "D->b address is : " << &d.b << endl;
    //cout << "D->func1 address is : " << (int*)&D::func1 << endl;
    printf ("D->func1 address is : %p \n", (void *)&d.func1);
    printf ("D->func2 address is : %p \n", (void *)&d.func2);
    printf ("D->func3 address is : %p \n", (void *)&d.func3);

    D _d;
    cout << "_D->b address is : " << &_d.b << endl; // 可以見得不同對象之間的成員變量存儲在不同的內存空間,但是同一個類的成員函數卻不一樣,都存在同一段代碼段中。

    //sub_for_virtual sub;
    ownerShip *ownership = new ownerShip ();
    ownership->coutAddress();

    verifyVar verifyvar;
    verifyvar.func ();

    // 很奇怪的存儲方式,不是順序結構,可能是鏈式結構
    cout << &e << endl;
    cout << &g << endl;
    cout << &f << endl;
    cout << &h << endl;

    //cout << "????";

    funcStorage funcstorage ;

    funcstorage.cout_();


    cout << endl;
    return 0;
}

 

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