c++中各類型數據所占字節數(二)


轉自:https://blog.csdn.net/allen_tony/article/details/76973906

https://blog.csdn.net/zzwdkxx/article/details/53635173

關於多個父類,虛繼承,類本身自己的虛函數,情況比較復雜,后續時間再研究。

 

 

類所占內存的大小是由成員變量(靜態變量除外)決定的,成員函數是不計算在內的。摘抄部分:
    成員函數還是以一般的函數一樣的存在。a.fun()是通過fun(a.this)來調用的。所謂成員函數只是在名義上是類里的。其實成員函數的大小不在類的對象里面,同一個類的多個對象共享函數代碼。而我們訪問成員函數是通過類里面的一個指針實現,而這個指針指向的是一個table,table里面記錄的各個成員函數的地址(當然不同的編譯可能略有不同的實現)。所以我們訪問成員函數是間接獲得地址的。所以這樣也就增加了一定的時間開銷,這也就是為什么我們提倡把一些簡短的,調用頻率高的函數聲明為inline形式(內聯函數)。

如果類定義了虛函數,該類及其派生類就要生成一張虛擬函數表,即vtable。而在類的對象地址空間中存儲一個該虛表的入口,占4個字節,這個入口地址是在構造對象時由編譯器寫入的。

所以,由於對象的內存空間包含了虛表入口,編譯器能夠由這個入口找到恰當的虛函數,這個函數的地址不再由數據類型決定了。

故對於一個父類的對象指針,調用虛擬函數,如果給他賦父類對象的指針,那么他就調用父類中的函數,如果給他賦子類對象的指針,他就調用子類中的函數(取決於對象的內存地址)。

 


(一)
class CBase
{
};
sizeof(CBase)=1;

為什么空的什么都沒有是1呢?

C++要求每個實例在內存中都有獨一無二的地址。    //important

空類也會被實例化,所以編譯器會給空類隱含的添加一個字節,這樣空類實例化之后就有了獨一無二的地址了。所以空類的sizeof為1.

(二)
class CBase
{
    int a;
    char p;
};
sizeof(CBase)=8;

記得對齊問題,64位是8字節對齊,32位是4字節對齊。int占4字節    //注意這點和struct的對齊原則很像!!!
char占一個字節,補齊3字節

(三)
class CBase
{
public:
    CBase(void);
    virtual ~CBase(void);
private:
    int a;
    char* p;
};

再運行:sizeof(CBase)=12

C++類中有虛函數的時候有一個指向虛函數的指針(vptr),在32位系統分配指針大小為4字節。無論多少個虛函數,只有這一個指針,4字節。//注意一般的函數是沒有這個指針的,而且也不占類的內存。

(四)
class CChild:public CBase
{
public:
    CChild(void);
    ~CChild(void);
    virtual void test();
private:
    int b;
};

輸出:sizeof(CChild)=16;

可見子類的大小是本身成員變量的大小加上父類的大小。//其中有一部分是虛函數表的原因,一定要知道
        父類子類共享一個虛函數指針。

(五)
#include <iostream>
class a{};
class b{};
class c:public a{
virtual void fun() = 0;
};
class d:[public b,public c{};
int main()
{
cout << "sizeof(a)=" << sizeof(a)<<endl;
cout << "sizeof(b)=" << sizeof(b)<<endl;
cout << "sizeof(c)=" << sizeof(c)<<endl;
cout << "sizeof(d)=" << sizeof(d)<<endl;
retrun 0;
}

程序執行的輸出結果為:
sizeof(a)=1
sizeof(b)=1
sizeof(c)=4
sizeof(d)=8

前三種情況比較常見,注意第四種情況。類d的大小更讓初學者疑惑,類d是由類b,c派生而來的,它所大小應該是二者之和5,為什么卻是8呢?這是因為為了提高實例在內存中的存取效率。類的大小往往被調整到系統的整數倍,並采取就近的法則,離哪最近的倍數就是該類的大小,所以類d的大小為8字節。

(六)

class MyClass { public: MyClass(); ~MyClass(); void test(); private: char p; }; MyClass::MyClass() { } MyClass::~MyClass() { } void MyClass::test() { } class MyClassA { public: MyClassA(); ~MyClassA(); public: static int m_a; }; MyClassA::MyClassA() { } MyClassA::~MyClassA() { } int MyClassA::m_a = 10; class MyClassB { public: MyClassB(); ~MyClassB(); virtual void test1(); virtual void test2(); private: }; MyClassB::MyClassB() { } void MyClassB::test1() { } void MyClassB::test2() { } MyClassB::~MyClassB() { } int main() { printf("MyClass's size is %d\n", sizeof(MyClass)); printf("MyClassA's size is %d\n", sizeof(MyClassA)); printf("MyClassB's size is %d\n", sizeof(MyClassB)); return 0; }

輸出

MyClass's size is 1
MyClassA's size is 1
MyClassB's size is 4

(七)繼承多個父類,父類都存在虛函數:

// y1.cpp : 定義控制台應用程序的入口點。
//

#include "stdafx.h"





class MyClassA
{
public:
    MyClassA();
    ~MyClassA();

    virtual void test1();

};

MyClassA::MyClassA()
{
}

MyClassA::~MyClassA()
{
}

void MyClassA::test1()
{

}


class MyClassB
{
public:
    MyClassB();
    ~MyClassB();

    virtual void test1();

private:

};

MyClassB::MyClassB()
{
}

void MyClassB::test1()
{
}


MyClassB::~MyClassB()
{
}

class MyClassC:public MyClassA
{
public:
    MyClassC();
    ~MyClassC();

private:

};

MyClassC::MyClassC()
{
}

MyClassC::~MyClassC()
{
}

class MyClassD: public MyClassA, MyClassB
{
public:
    MyClassD();
    ~MyClassD();

private:

};

MyClassD::MyClassD()
{

}

MyClassD::~MyClassD()
{

}

int main()
{
    
    printf("MyClass's size is %d\n", sizeof(MyClassA));

    printf("MyClassA's size is %d\n", sizeof(MyClassB));

    printf("MyClassB's size is %d\n", sizeof(MyClassC));

    printf("MyClassB's size is %d\n", sizeof(MyClassD));

    return 0;
}

輸出:

MyClassA's size is 4
MyClassB's size is 4
MyClassC's size is 4
MyClassD's size is 8

MyClassA,MyClassB都有虛函數。MyClassD繼承了MyClassA和MyClassB,所以

MyClassD占用的空間為8

 

總結:
空的類是會占用內存空間的,而且大小是1,原因是C++要求每個實例在內存中都有獨一無二的地址。
(一)類內部的成員變量:
普通的變量:是要占用內存的,但是要注意對齊原則(這點和struct類型很相似)。
static修飾的靜態變量:不占用內容,原因是編譯器將其放在全局變量區。
(二)類內部的成員函數:
普通函數:不占用內存。虛函數:要占用4個字節,用來指定虛函數的虛擬函數表的入口地址。所以一個類的虛函數所占用的地址是不變的,和虛函數的個數是沒有關系的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM