c++中各種型數據所佔字節數(二)

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

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

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

 

 

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

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

因此,因爲對象的內存空間包含了虛表入口,編譯器可以由這個入口找到恰當的虛函數,這個函數的地址再也不由數據類型決定了。指針

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

 


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

爲何空的什麼都沒有是1呢?blog

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個字節,用來指定虛函數的虛擬函數表的入口地址。因此一個類的虛函數所佔用的地址是不變的,和虛函數的個數是沒有關係的。

相關文章
相關標籤/搜索