偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

深入C++核心:空類(lèi)背后隱藏的內(nèi)存開(kāi)銷(xiāo),你知道嗎?

開(kāi)發(fā)
本文讓我們一起揭開(kāi)C++空類(lèi)的神秘面紗,探索這個(gè)看似簡(jiǎn)單卻暗藏玄機(jī)的話題。

你有沒(méi)有想過(guò),一個(gè)空的購(gòu)物袋到底有多重????

即使是空的,它也占據(jù)著一定的空間,對(duì)吧?在C++的世界里,我們也有類(lèi)似的情況 - 空類(lèi)(Empty Class)??雌饋?lái)什么都沒(méi)有,但它真的一點(diǎn)內(nèi)存都不占嗎?

讓我們一起揭開(kāi)C++空類(lèi)的神秘面紗,探索這個(gè)看似簡(jiǎn)單卻暗藏玄機(jī)的話題。相信我,這個(gè)旅程會(huì)很有趣!

最簡(jiǎn)單的空類(lèi)

想象一下,你正在收拾房間,把所有東西都清空了。那么問(wèn)題來(lái)了:一個(gè)空房間還占地方嗎?

在C++中,我們也有類(lèi)似的問(wèn)題:一個(gè)空空如也的類(lèi)會(huì)占用內(nèi)存空間嗎?讓我們一起來(lái)探索這個(gè)有趣的謎題!

來(lái)看看最簡(jiǎn)單的空類(lèi):

class Empty {};

// 測(cè)試一下它的大小
cout << sizeof(Empty) << endl;  // 驚喜:輸出是1!

咦?明明什么都沒(méi)有,為什么還要占用1個(gè)字節(jié)呢?

這就像是你在小區(qū)里買(mǎi)房子 - 即使是空房子,也需要有門(mén)牌號(hào),對(duì)吧!在C++中,每個(gè)對(duì)象都需要有自己的內(nèi)存地址(相當(dāng)于門(mén)牌號(hào)),所以編譯器會(huì)給每個(gè)空類(lèi)安排至少1個(gè)字節(jié)的空間。

為什么需要這一個(gè)字節(jié)?

這個(gè)1字節(jié)的存在有著非常重要的意義!它就像是每個(gè)對(duì)象的身份證:

Empty e1, e2;   // 創(chuàng)建兩個(gè)空類(lèi)對(duì)象

這1字節(jié)的主要作用是:

  • 確保每個(gè)對(duì)象都有唯一的內(nèi)存地址
  • 使得對(duì)象可以被定位和區(qū)分
  • 滿足C++標(biāo)準(zhǔn)要求的對(duì)象必須具有非零大小的規(guī)定

等等,這里可能有個(gè)疑問(wèn):既然是內(nèi)存地址,為什么不是8字節(jié)(64位系統(tǒng))或4字節(jié)(32位系統(tǒng))呢???

這里需要區(qū)分兩個(gè)概念:

  • 對(duì)象本身占用的內(nèi)存大小
  • 指向?qū)ο蟮闹羔樀拇笮?/li>

讓我們用代碼來(lái)說(shuō)明:

Empty e;              // 對(duì)象本身占 1 字節(jié)
Empty* ptr = &e;      // 指針占 8 字節(jié)(在64位系統(tǒng)上)

cout << sizeof(e) << endl;    // 輸出:1
cout << sizeof(ptr) << endl;  // 輸出:8

就像門(mén)牌號(hào)和GPS坐標(biāo)的關(guān)系:

  • 門(mén)牌號(hào)(對(duì)象本身)只需要很小的空間就能標(biāo)識(shí)這個(gè)位置
  • GPS坐標(biāo)(指針)需要更多的數(shù)字來(lái)精確定位

編譯器只需要1個(gè)字節(jié)就能區(qū)分不同的對(duì)象,而指向這些對(duì)象的指針則需要更大的空間來(lái)存儲(chǔ)完整的內(nèi)存地址。這是一個(gè)很巧妙的設(shè)計(jì)!

為什么對(duì)象必須有不同的地址呢?這關(guān)系到C++的一個(gè)基本原則:

Empty* ptr1 = &e1;
Empty* ptr2 = &e2;
assert(ptr1 != ptr2);  // 這個(gè)斷言永遠(yuǎn)為真,因?yàn)槊總€(gè)對(duì)象必須有唯一地址

就像在一個(gè)小區(qū)里,即使是完全相同的兩套房子,也必須有不同的門(mén)牌號(hào)。這個(gè)1字節(jié)就相當(dāng)于對(duì)象的"門(mén)牌號(hào)",讓系統(tǒng)能夠準(zhǔn)確找到并區(qū)分每一個(gè)對(duì)象!

虛擬繼承大冒險(xiǎn)

嘿!讓我們來(lái)玩?zhèn)€有趣的游戲 - 建造屬于我們的動(dòng)物王國(guó)!

首先,我們需要一個(gè)動(dòng)物祖先:

class Animal {};  // ?? 萬(wàn)物之源!

然后,讓我們召喚一些可愛(ài)的小動(dòng)物:

class Cat : public virtual Animal {};  // ?? 喵星來(lái)客
class Dog : public virtual Animal {};  // ?? 汪星使者

咦?這些小可愛(ài)的"體重"是多少呢?讓我們偷偷稱(chēng)一下:

cout << sizeof(Cat) << endl;   // 8字節(jié)!??

哇塞!一個(gè)空空的貓咪居然有8字節(jié)這么重!這是為啥呢?

原來(lái)啊,每個(gè)虛擬繼承的小動(dòng)物都帶著一個(gè)神奇的指南針:

  • 這個(gè)指南針幫它們找到Animal祖先
  • 就像GPS定位器一樣不能丟
  • 在64位系統(tǒng)上,這個(gè)指南針要占8個(gè)字節(jié)呢!

來(lái)看個(gè)更有意思的 - 動(dòng)物園時(shí)間!

class Zoo {
    Cat kitty;    // ?? 一只優(yōu)雅的喵
    Dog puppy;    // ?? 一只活潑的汪
};

猜猜動(dòng)物園有多大?

cout << sizeof(Zoo) << endl;  // 16字節(jié)!??

哈!16字節(jié) = 8(喵) + 8(汪) ?? 就像兩個(gè)小朋友各自背著自己的小書(shū)包!

小提示:

  • 虛擬繼承雖然酷炫,但也要付出代價(jià)哦!
  • 如果你的程序想要"減肥",可要慎用這個(gè)功能!

看,C++也可以這么可愛(ài)對(duì)吧?記?。好總€(gè)設(shè)計(jì)都像選擇玩具一樣,要想清楚它的代價(jià)哦!

多重繼承的奇妙冒險(xiǎn)

哈嘍!今天我們要?jiǎng)?chuàng)造一個(gè)超級(jí)神奇的生物 - 既是貓又是狗的小可愛(ài)!

class CatDog : public Cat, public Dog {};  // 喵星汪星合體! ????

猜猜這個(gè)小家伙有多重? 

cout << sizeof(CatDog) << endl;  // 哇塞!8字節(jié)耶! ??

為啥是8字節(jié)呢?讓我們來(lái)解剖一下這個(gè)有趣的現(xiàn)象:

(1) 首先,Cat類(lèi)帶著8字節(jié):

  • 其中包含了指向Animal虛表的指針(在64位系統(tǒng)上是8字節(jié))

(2) Dog類(lèi)也帶著8字節(jié):

  • 同樣包含指向Animal虛表的指針

(3) 但是這里有個(gè)巧妙的地方:

  • Cat和Dog都是虛繼承自Animal
  • 它們共享同一個(gè)Animal基類(lèi)實(shí)例
  • 在內(nèi)存布局中,只需要保存一份Animal的虛表指針
  • 這就是為什么要減去4字節(jié)(32位系統(tǒng))或8字節(jié)(64位系統(tǒng))

(4) 所以最終的計(jì)算公式是:

  • 在32位系統(tǒng):4 + 4 - 4 = 4字節(jié)
  • 在64位系統(tǒng):8 + 8 - 8 = 8字節(jié)

就像兩個(gè)小朋友(Cat和Dog)共用一本相冊(cè)(Animal的信息)一樣,沒(méi)必要每人都帶一本相同的!這就是C++編譯器的智慧! 

小彩蛋:有些聰明的編譯器會(huì)給它們做個(gè)"瘦身" 

  • 通過(guò)優(yōu)化內(nèi)存對(duì)齊和布局
  • 可能會(huì)得到更小的實(shí)際大小
  • 這種優(yōu)化被稱(chēng)為"Empty Base Optimization"(EBO)

記?。翰煌幾g器就像不同的魔法師,各有各的獨(dú)門(mén)絕技!但只要理解了原理,你就能成為C++世界的小達(dá)人啦! 

更復(fù)雜的繼承場(chǎng)景

先來(lái)個(gè)小提示:還記得虛繼承是做什么的嗎?

// 沒(méi)有虛繼承時(shí)的菱形繼承問(wèn)題
class Animal {};
class Bird :public Animal {};
class Fish :public Animal {};
class Flying_Fish :public Bird, public Fish {};  // 兩份Animal!

// 使用虛繼承解決
class Bird :virtualpublic Animal {};  // 只保留一份Animal
class Fish :virtualpublic Animal {};  // 但需要額外的內(nèi)存開(kāi)銷(xiāo)

虛繼承就像是給類(lèi)們安排了一個(gè)共享的基類(lèi)空間,解決了重復(fù)繼承的問(wèn)題。不過(guò)這個(gè)便利是要付出內(nèi)存代價(jià)的!

讓我們來(lái)玩?zhèn)€更刺激的游戲 - 多層繼承大冒險(xiǎn)!

先來(lái)個(gè)基礎(chǔ)款超能力:

class SuperPower {
    virtual void activate() {}  // 激活超能力!?
};

再來(lái)個(gè)進(jìn)階版超能力:

class MegaPower : public virtual SuperPower {
    virtual void powerUp() {}  // 能量加倍!??
};

哎呀!這時(shí)候事情變得有趣了:

cout << sizeof(SuperPower) << endl;  // 8字節(jié) - 因?yàn)樘摵瘮?shù)表指針 ??
cout << sizeof(MegaPower) << endl;   // 16字節(jié) - 雙倍的快樂(lè)!??

為啥是16字節(jié)呢?讓我們拆開(kāi)看看這個(gè)"超能力包裹":

  • 8字節(jié)用來(lái)存虛函數(shù)表指針
  • 8字節(jié)用來(lái)存虛基類(lèi)指針
  • 就像雙層漢堡一樣,每層都很重要!

(1) 虛函數(shù)表指針(vptr,8字節(jié))

  • 這是一個(gè)指向虛函數(shù)表(vtable)的指針
  • 虛函數(shù)表存儲(chǔ)了所有虛函數(shù)的地址
  • 用于實(shí)現(xiàn)動(dòng)態(tài)多態(tài),使得程序能在運(yùn)行時(shí)決定調(diào)用哪個(gè)版本的虛函數(shù)
  • 就像一本"說(shuō)明書(shū)",告訴對(duì)象:"你的超能力們都藏在哪里"

(2) 虛基類(lèi)指針(vbptr,8字節(jié))

  • 這個(gè)指針指向虛基類(lèi)表(virtual base table)
  • 用于在運(yùn)行時(shí)定位虛基類(lèi)的位置
  • 解決菱形繼承問(wèn)題,確保虛基類(lèi)只有一個(gè)實(shí)例
  • 就像一個(gè)"導(dǎo)航儀",幫助對(duì)象找到它的祖先類(lèi)

來(lái)個(gè)形象的比喻:

class MegaPower : public virtual SuperPower {
    virtual void powerUp() {}
};
  • 虛函數(shù)表指針就像游戲手柄,控制著不同的技能按鍵(虛函數(shù))
  • 虛基類(lèi)指針則像是族譜導(dǎo)航,幫助找到共同的祖先(虛基類(lèi))

來(lái)個(gè)更瘋狂的 - 超級(jí)英雄時(shí)間!

class SuperHero : public virtual MegaPower {
    virtual void fly() {}  // 飛天遁地!??
};

猜猜看這位英雄的"體重"?

cout << sizeof(SuperHero) << endl;  // 16字節(jié) - 咦,沒(méi)變重誒!??

為什么沒(méi)變重?因?yàn)椋?/p>

  • 虛繼承只需要一個(gè)虛表指針
  • 所有的虛函數(shù)共享同一個(gè)虛表
  • 這就是C++的魔法!

小貼士:記住這個(gè)公式

  • 普通類(lèi) + 虛函數(shù) = 8字節(jié)(64位系統(tǒng))
  • 加上虛繼承 = 16字節(jié)
  • 再多繼承也不會(huì)更重啦?。ǔ羌恿诵鲁蓡T)

就像疊疊樂(lè)游戲,有技巧才不會(huì)倒!

優(yōu)化技巧與注意事項(xiàng) 

來(lái)看看如何給我們的類(lèi)"減肥"吧! 

(1) 巧用空基類(lèi)優(yōu)化 (EBO) 

// 不好的寫(xiě)法 - 浪費(fèi)內(nèi)存
class MyClass {
    EmptyBase base;  // 占1字節(jié)
    int data;        // 占4字節(jié),但可能因?qū)R變成8字節(jié)
};

// 聰明的寫(xiě)法 - 節(jié)省空間
class MyClass : private EmptyBase {
    int data;  // 只占4字節(jié),EmptyBase不占額外空間
};

這就像是把空書(shū)包直接背在身上,而不是放在行李箱里! ??

(2) 合理使用虛繼承

// 需要虛繼承時(shí)才用它
class Bird : virtual public Animal {};  // ??

// 普通情況用普通繼承就好
class Cat : public Animal {};  // ?? 省內(nèi)存!

(3) 對(duì)齊小魔法

class SmartClass {
    char flag;     // 1字節(jié)
    int data;      // 4字節(jié)
    char status;   // 1字節(jié)
};  // 實(shí)際占12字節(jié),因?yàn)閷?duì)齊!

// 優(yōu)化后:
class SmartClass {
    int data;      // 4字節(jié)
    char flag;     // 1字節(jié)
    char status;   // 1字節(jié)
};  // 現(xiàn)在只占8字節(jié)啦! 

把小件物品巧妙放置,就像俄羅斯方塊一樣! 

總結(jié)要點(diǎn)

讓我們來(lái)個(gè)歡樂(lè)總結(jié)吧! 

(1) 空類(lèi)的秘密

  • 空類(lèi)占1字節(jié) - 就像空房子也要有門(mén)牌號(hào)! 
  • 指針永遠(yuǎn)是固定大小(32位4字節(jié)/64位8字節(jié)) 

(2) 繼承的趣事

class Empty {};           // 1字節(jié)
class Virtual {          // 8字節(jié)
    virtual void foo();  // 因?yàn)樘摵瘮?shù)表指針
};

(3) 內(nèi)存對(duì)齊小貼士

  • 就像疊積木,要整整齊齊! 
  • 合理布局可以省下不少空間 

(4) 實(shí)用建議

  • 不需要虛函數(shù)就別用 
  • 善用EBO來(lái)節(jié)省空間 
  • 把相同大小的成員放一起 

記住:優(yōu)化很重要,但代碼可讀性更重要! 平衡最美! 

這就是C++的空類(lèi)世界啦! 雖然看起來(lái)空空的,但學(xué)問(wèn)可不少呢! ??

責(zé)任編輯:趙寧寧 來(lái)源: everystep
相關(guān)推薦

2022-10-11 08:14:14

多線程鎖機(jī)制

2023-12-12 08:41:01

2021-09-13 19:28:42

JavaNetty開(kāi)發(fā)

2024-09-12 08:20:39

2025-01-26 16:01:13

C++靜態(tài)成員函數(shù)

2019-12-12 09:23:29

Hello World操作系統(tǒng)函數(shù)庫(kù)

2022-03-10 08:25:27

JavaScrip變量作用域

2022-02-25 08:13:03

物聯(lián)網(wǎng)IOT

2021-10-14 06:52:47

算法校驗(yàn)碼結(jié)構(gòu)

2022-09-29 15:32:58

云計(jì)算計(jì)算模式

2024-09-18 07:00:00

消息隊(duì)列中間件消息隊(duì)列

2023-04-26 10:21:04

2023-12-20 08:23:53

NIO組件非阻塞

2024-04-30 09:02:48

2021-09-19 22:51:49

iPhone手機(jī)iOS

2024-04-07 00:00:00

ESlint命令變量

2024-05-28 09:12:10

2024-11-01 10:48:01

C#WPF程序

2017-10-13 11:13:16

微信隱藏功能視頻編輯

2022-12-06 10:04:59

5G網(wǎng)絡(luò)C波段
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)