最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

由static_cast和dynamic_cast到C++對(duì)象占用內(nèi)存的全面分析

 更新時(shí)間:2017年01月05日 09:29:55   投稿:jingxian  
下面小編就為大家?guī)?lái)一篇由static_cast和dynamic_cast到C++對(duì)象占用內(nèi)存的全面分析。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

static_cast和dynamic_cast是C++的類型轉(zhuǎn)換操作符。編譯器隱式執(zhí)行的任何類型轉(zhuǎn)換都可以由static_cast顯式完成,即父類和子類之間也可以利用static_cast進(jìn)行轉(zhuǎn)換。而dynamic_cast只能用于類之間的轉(zhuǎn)換。那么dynamic_cast的存在還有什么意義呢?因?yàn)閐ynamic_cast提供了一個(gè)重要的特性:運(yùn)行時(shí)類型檢查來(lái)保證轉(zhuǎn)換的安全性。

用static_cast轉(zhuǎn)換存在的危險(xiǎn)

我們知道,一個(gè)基類指針不需要進(jìn)行明確的轉(zhuǎn)換操作,就可以指向基類對(duì)象或者派生類對(duì)象。比如:

class Base{
  //…
};
class Derived{
  //…
};
int main{
  Base *p = new Base();//OK
  Base *p = new Derived();//OK
}

上面的兩種定義都是正確的,那么如果想反過(guò)來(lái),讓一個(gè)子類指針指向父類對(duì)象呢?如下代碼:

class Base{
  //…
};
class Derived{
  //…
};
int main{
  Derived *p = new Base();//error
  Derived *p = static_cast<Derived*>(new Base());//OK
}

如果直接把Base類型的指針轉(zhuǎn)換為Derived類型的指針,那么編譯時(shí)會(huì)報(bào)錯(cuò)。如果在轉(zhuǎn)換時(shí)加上static操作符則可以順利通過(guò)編譯。但是這種做法是十分危險(xiǎn)的,在運(yùn)行期時(shí)可能會(huì)出現(xiàn)一些難以預(yù)測(cè)和查找的錯(cuò)誤。如下面代碼:

class Base{
  public:
    Base():m_b(4){};
    int m_b;
void m_funcB(){cout << "base" << endl;};
};
class Derived:public Base{
  public:
    Derived():m_d(3){};
    int m_d;
    void m_funcD(){cout << "derived" << endl;};
};
int main(){
  Derived* p = static_cast<Derived*>(new Base());
  cout << p->m_d << endl;
  p->m_funcD();
}


雖然p是Derived類型的指針,但是實(shí)際卻指向了Base對(duì)象,而Base對(duì)象不存在m_d這個(gè)數(shù)據(jù)成員,因此輸出的結(jié)果不可預(yù)測(cè)(在我的機(jī)子上一直輸出0)。正是這種不可預(yù)測(cè)才導(dǎo)致難以追蹤的錯(cuò)誤,試想,如果執(zhí)行這段代碼會(huì)崩潰,那么還是比較還排查的,但是現(xiàn)在并不一定崩潰,只是執(zhí)行的結(jié)果和我們的預(yù)測(cè)不一致,可能將導(dǎo)致連環(huán)的邏輯錯(cuò)誤,這就像給自己挖了一個(gè)坑或者定時(shí)炸彈。

但是很奇怪的一點(diǎn)是,執(zhí)行p->m_funcD()這一句后,居然可以打印出”derived”。這是怎么回事?m_funcD明明是類Derived的函數(shù),而且類Base里并不存在這個(gè)函數(shù),這個(gè)我們留在后面說(shuō)明。

利用dynamic_cast保證轉(zhuǎn)換的安全

原則上,我們不應(yīng)該讓子類指針指向父類的對(duì)象。但是如果寫下了上面這樣的代碼,我們希望可以有一種檢查機(jī)制可以幫助我們發(fā)現(xiàn)這個(gè)問(wèn)題,這樣就可以避免對(duì)轉(zhuǎn)換后的指針進(jìn)行操作,造成不可預(yù)料的后果。

C++是支持運(yùn)行期類型識(shí)別的(RTTI),這種機(jī)制除了幫助我們實(shí)現(xiàn)多態(tài),還能在類型轉(zhuǎn)換時(shí)進(jìn)行安全檢查?;氐缴厦娴拇a,我們稍作修改:

class Base{
  public:
    Base():m_b(4){};
    int m_b;
    virtual void m_funcB(){cout << "base" << endl;};
};

class Derived:public Base{
  public:
    Derived():m_d(3){};
    int m_d;
    void m_funcD(){cout << "derived" << endl;};
};
int main(){
  Derived* p = dynamic_cast<Derived*>(new Base());
  cout << p->m_d << endl;
  p->m_funcD();
}

運(yùn)行結(jié)果會(huì)是什么?程序崩潰了。原因就是我們執(zhí)行了p->m_d,而p這個(gè)時(shí)候是一個(gè)空指針。原因在于利用dynamic_cast進(jìn)行類型轉(zhuǎn)換時(shí)會(huì)進(jìn)行安全檢查,在這里我們將一個(gè)父類指針轉(zhuǎn)換為子類指針,這被認(rèn)為是一個(gè)無(wú)效操作,因此返回NULL,因此p成了空指針。所以當(dāng)我們利用dynamic_cast進(jìn)行了轉(zhuǎn)換后,只要對(duì)得到的指針進(jìn)行檢查,就可以知道轉(zhuǎn)換是否成功。static_cast則沒(méi)有提供這種檢查,這就是dynamic_cast比static_cast安全的原因。

現(xiàn)在稍微離開一下正題,如果把打印m_d這句注釋掉,執(zhí)行p->m_funcD()這一句后,發(fā)現(xiàn)還是能夠打印出”derived”。等我們總結(jié)dynamic_cast和static_cast的區(qū)別后就對(duì)這個(gè)現(xiàn)象進(jìn)行討論。

dynamic_cast和static_cast的區(qū)別:

dynamic_cast可以實(shí)現(xiàn)運(yùn)行期類型安全檢查,是一種更加安全的方法,但是僅僅對(duì)多態(tài)類型有效,而且只能用于指針或者引用類型的轉(zhuǎn)換上。static_cast則可應(yīng)用與任何類型,而且不需要類型實(shí)現(xiàn)了多態(tài)。static_cast的應(yīng)用更加廣泛,但是dynamic_cast更加強(qiáng)大和安全。

對(duì)象占用內(nèi)存分析:

下面看一下我們兩次提到的現(xiàn)象:為什么通過(guò)一個(gè)實(shí)際指向了基類對(duì)象的子類指針調(diào)用子類的方法,既然沒(méi)有出現(xiàn)錯(cuò)誤并且可以順利調(diào)用?

一個(gè)類無(wú)非就是包含兩種成員:數(shù)據(jù)和方法。那么當(dāng)我們實(shí)例化出一個(gè)對(duì)象的時(shí)候,這個(gè)對(duì)象包含了哪些東西,實(shí)際占用的內(nèi)存大小是多少?寫一段代碼試一試:

class Base{
  public:
    Base():m_b(4){};
    int m_b;
    virtual void m_funcB(){cout << "base" << endl;};
};
class Derived:public Base{
  public:
    Derived():m_d(3){};
    int m_d;
    void m_funcD(){cout << "derived" << endl;};
};
int main(){
  cout << sizeof(Base) << endl;  
  cout << sizeof(Derived) << endl;
}

打印出的結(jié)果分別是8和12。

那么一個(gè)類或者說(shuō)對(duì)象占用的內(nèi)存到底怎么計(jì)算呢?以Base為例,首先成員變量m_b占用了4個(gè)字節(jié),其次,由于m_funcB是虛函數(shù),因此要有一張?zhí)摵瘮?shù)表,其實(shí)就是一個(gè)指向表的指針,無(wú)論是什么類型的指針,占用的大小總是4字節(jié),因此base占用了8個(gè)字節(jié)的大小。而Derived除了繼承了Base的成員m_b之外,也保存了虛函數(shù)表的地址,還有自己的成員變量m_d,所以占用了12個(gè)字節(jié)。

或者有人會(huì)問(wèn):構(gòu)造函數(shù)呢?還有虛函數(shù)本身不是還有函數(shù)體嗎?難道不用計(jì)算進(jìn)去?確實(shí),類的函數(shù)是不會(huì)存儲(chǔ)在實(shí)例化出來(lái)的對(duì)象里的,試想,對(duì)于每個(gè)對(duì)象,函數(shù)實(shí)現(xiàn)都是一樣的,如果每實(shí)例化一個(gè)對(duì)象就存儲(chǔ)一次函數(shù)體,不是毫無(wú)必要并且對(duì)內(nèi)存使用而言是極大的浪費(fèi)?

函數(shù)編譯出來(lái)后是作為代碼的一部分放在代碼段中的,因此只要我們定義了Derived指針,無(wú)論這個(gè)實(shí)際指針指向什么對(duì)象,由于程序“事先”已經(jīng)知道了這個(gè)方法屬于哪個(gè)類,只要指針的類型正確,都可以正確找到調(diào)用函數(shù)的入口。所以即使我們的代碼這么寫,也是可以正確運(yùn)行的:

void * p2 = (int*)0;
Derived* p3= (Derived*)p2;
cout << p3->m_funcD() << endl;

不管把什么地址賦給p2,都能正確地執(zhí)行m_funcD函數(shù)。當(dāng)然如果p3定義成其他類型,那么編譯就會(huì)出錯(cuò)。

如果執(zhí)行以下代碼:

void * p2 = (int*)0;
Derived* p3= (Derived*)p2;
cout << p3->m_d << endl;

那么程序就會(huì)出現(xiàn)錯(cuò)誤了,因?yàn)楹统蓡T函數(shù)不同,成員變量是每個(gè)對(duì)象都會(huì)在內(nèi)存中用實(shí)際的內(nèi)存地址存儲(chǔ),所以說(shuō)成員函數(shù)屬于類,成員變量屬于各自的對(duì)象。

以上就是小編為大家?guī)?lái)的由static_cast和dynamic_cast到C++對(duì)象占用內(nèi)存的全面分析全部?jī)?nèi)容了,希望大家多多支持腳本之家~

相關(guān)文章

  • C++中靜態(tài)庫(kù)與動(dòng)態(tài)庫(kù)的使用示例

    C++中靜態(tài)庫(kù)與動(dòng)態(tài)庫(kù)的使用示例

    在C/C++中使用庫(kù)的技術(shù),庫(kù)主要分為兩種類型:靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù),本文主要介紹了C++中靜態(tài)庫(kù)與動(dòng)態(tài)庫(kù)的使用示例,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-09-09
  • 詳解VS2019 dumpbin查看DLL的導(dǎo)出函數(shù)

    詳解VS2019 dumpbin查看DLL的導(dǎo)出函數(shù)

    這篇文章主要介紹了詳解VS2019 dumpbin查看DLL的導(dǎo)出函數(shù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • C++利用類實(shí)現(xiàn)矩陣的數(shù)乘,乘法以及點(diǎn)乘

    C++利用類實(shí)現(xiàn)矩陣的數(shù)乘,乘法以及點(diǎn)乘

    這篇文章主要為大家詳細(xì)介紹了C++如何利用類實(shí)現(xiàn)矩陣的數(shù)乘,乘法以及點(diǎn)乘,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C++有一定幫助,需要的可以參考一下
    2022-11-11
  • C++學(xué)習(xí)小結(jié)之?dāng)?shù)據(jù)類型及轉(zhuǎn)換方式

    C++學(xué)習(xí)小結(jié)之?dāng)?shù)據(jù)類型及轉(zhuǎn)換方式

    本文給大家分享的是本人在學(xué)習(xí)C++過(guò)程中的一個(gè)小心得,關(guān)于數(shù)據(jù)類型和轉(zhuǎn)換方式的,這里記錄下來(lái),推薦給菜鳥們,高手大神請(qǐng)直接飄過(guò)。
    2015-07-07
  • C++11中的智能指針shared_ptr、weak_ptr源碼解析

    C++11中的智能指針shared_ptr、weak_ptr源碼解析

    本文是基于gcc-4.9.0的源代碼進(jìn)行分析,shared_ptr和weak_ptr是C++11才加入標(biāo)準(zhǔn)的,僅對(duì)C++智能指針shared_ptr、weak_ptr源碼進(jìn)行解析,需要讀者有一定的C++基礎(chǔ)并且對(duì)智能指針有所了解
    2021-09-09
  • 關(guān)于在C程序中處理UTF-8文本的方法詳解

    關(guān)于在C程序中處理UTF-8文本的方法詳解

    這篇文章主要給大家介紹了關(guān)于在C程序中處理UTF-8文本的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-11-11
  • 一篇文章帶你了解C語(yǔ)言指針進(jìn)階

    一篇文章帶你了解C語(yǔ)言指針進(jìn)階

    這篇文章主要介紹了C語(yǔ)言指針詳解及用法示例,介紹了其相關(guān)概念,然后分享了幾種用法,具有一定參考價(jià)值。需要的朋友可以了解下
    2021-09-09
  • QT編寫簡(jiǎn)單登錄界面的實(shí)現(xiàn)示例

    QT編寫簡(jiǎn)單登錄界面的實(shí)現(xiàn)示例

    登陸界面是網(wǎng)頁(yè)中常見的界面,本文主要介紹了QT編寫簡(jiǎn)單登錄界面的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • 利用C++ R3層斷鏈實(shí)現(xiàn)模塊隱藏功能

    利用C++ R3層斷鏈實(shí)現(xiàn)模塊隱藏功能

    在R3層的模塊隱藏,我們需要做的就是將其該鏈表斷鏈,將某一模塊從這個(gè)雙向鏈表中摘除,這樣再調(diào)用傳統(tǒng)的API時(shí)就會(huì)搜索不到。本文重點(diǎn)給大家介紹利用C++ R3層斷鏈實(shí)現(xiàn)模塊隱藏功能,感興趣的朋友一起看看吧
    2019-10-10
  • Qt實(shí)現(xiàn)進(jìn)程界面之間的鼠標(biāo)焦點(diǎn)切換

    Qt實(shí)現(xiàn)進(jìn)程界面之間的鼠標(biāo)焦點(diǎn)切換

    這篇文章主要為大家詳細(xì)介紹了Qt實(shí)現(xiàn)進(jìn)程界面之間的鼠標(biāo)焦點(diǎn)切換,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-09-09

最新評(píng)論

竹北市| 万年县| 茂名市| 济阳县| 桃园市| 甘南县| 河源市| 贡觉县| 大安市| 商丘市| 织金县| 米脂县| 黄陵县| 临泽县| 山丹县| 大荔县| 比如县| 雅安市| 涟源市| 获嘉县| 襄城县| 漳平市| 通山县| 常山县| 武乡县| 商都县| 天水市| 泸定县| 青神县| 临沂市| 浦东新区| 松原市| 乌鲁木齐县| 宣威市| 胶南市| 商丘市| 五台县| 安宁市| 凉城县| 万山特区| 湖北省|