c++ 有趣的動態(tài)轉(zhuǎn)換
緣起
最近,在項目代碼中看到一個非常神奇的類型轉(zhuǎn)換—— 類型A 的指針居然能動態(tài)轉(zhuǎn)換成另外一個完全沒有任何關(guān)系的類指針。這…… 完全顛覆了我的認(rèn)知。
為了進(jìn)一步了解這個神奇的操作,我特意模擬了項目代碼中的情形,一起來看看吧。
代碼簡介
BaseA
和 BaseB
是兩個基類,NewA
繼承自 BaseA
,NewB
繼承自 BaseB
。TestB()
會在堆上 new
一個 NewB
的對象,但是會強制轉(zhuǎn)換成 BaseA
類型的指針并返回(這個操作太逆天,大家一定不要在項目代碼中這么玩兒)。main()
函數(shù)中模擬使用和釋放。背景介紹完畢,看代碼。
測試代碼 1
#include "stdafx.h" #include "stdlib.h" class BaseA { public: virtual void AA() = 0; virtual ~BaseA() {}; }; class NewA : public BaseA { public: ~NewA() { printf(__FUNCTION__ "\n"); } virtual void AA() override { printf(__FUNCTION__ "\n"); } }; class BaseB { public: virtual void BB() = 0; virtual ~BaseB() {}; }; class NewB : public BaseB { public: virtual ~NewB() { printf(__FUNCTION__ "\n"); } virtual void BB() override { printf(__FUNCTION__ "\n"); } }; BaseA* TestB() { NewB *pNewB = new NewB(); return (BaseA*)pNewB; } int _tmain(int argc, _TCHAR* argv[]) { BaseA* pBaseA = TestB(); BaseB *pBaseB = (BaseB *)pBaseA; delete(pBaseA); system("pause"); return 0; }
上面的代碼有什么問題嗎?運行結(jié)果是:一切正常。
but……
測試代碼 2
相對于 測試代碼1,測試代碼2 中調(diào)用了虛函數(shù),只改變了 main 中的調(diào)用部分。
int _tmain(int argc, _TCHAR* argv[]) { BaseA* pBaseA = TestB(); BaseB *pBaseB = (BaseB *)pBaseA; // added part: call virtual functions pBaseA->AA(); pBaseB->BB(); delete(pBaseA); system("pause"); return 0; }
上面的代碼會輸出什么呢?
pBaseA->AA()
的輸出結(jié)果是 NewB::BB
。有些“意外”,但是卻在情理之中。下一篇會比較詳細(xì)的剖析虛函數(shù)調(diào)用機制,知道運作及之后,再回過頭來看這個問題就很容易理解了!
測試代碼 3
相對于 測試代碼2,測試代碼 3 只為 BaseB
增加了一個名為 PerfectFunctionName()
的接口,并在子類NewB
中實現(xiàn)了這個接口。其它部分不變。這里只列出變化的部分。
#include "stdafx.h" #include "stdlib.h" class BaseB { public: virtual void BB() = 0; virtual void PerfectFunctionName() = 0; // Added part virtual ~BaseB() {}; }; class NewB : public BaseB { public: virtual ~NewB() { printf(__FUNCTION__ "\n"); } virtual void BB() override { printf(__FUNCTION__ "\n"); } virtual void PerfectFunctionName() override { printf(__FUNCTION__ "\n"); } // Added part };
最新代碼運行結(jié)果會是什么樣的呢?
上圖是 32 位 debug
版程序運行時的輸出結(jié)果。終于報了異常!release
版運行后也會報異常!
從測試結(jié)果可知,這種做法在某些情況下確實可以正常運行,但是某些情況下會得到一些奇怪的結(jié)果,甚至?xí)l(fā)生崩潰。這些現(xiàn)象背后的原因我想留到后面幾篇文章分析。感興趣的小伙伴兒可以手動測試并分析。
結(jié)論
永遠(yuǎn)不要做這種危險的 SAO 操作!
以上就是c++ 動態(tài)轉(zhuǎn)換的詳細(xì)內(nèi)容,更多關(guān)于c++ 動態(tài)轉(zhuǎn)換的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
c++中strcpy函數(shù)在VS2015無法使用的問題
這篇文章主要介紹了c++中strcpy函數(shù)在VS2015無法使用的問題,具有一定的參考價值,有需要的可以了解一下。2016-11-11詳解C語言用malloc函數(shù)申請二維動態(tài)數(shù)組的實例
這篇文章主要介紹了詳解C語言用malloc函數(shù)申請二維動態(tài)數(shù)組的實例的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下2017-10-10利用簡潔的C語言代碼解決跳臺階問題與約瑟夫環(huán)問題
這篇文章主要介紹了利用簡潔的C語言代碼解決跳臺階問題與約瑟夫環(huán)問題的方法,跳臺階問題與約瑟夫環(huán)問題是常見的基礎(chǔ)算法題目,需要的朋友可以參考下2016-02-02詳解C語言如何計算結(jié)構(gòu)體大小(結(jié)構(gòu)體的內(nèi)存對齊)
結(jié)構(gòu)體的內(nèi)存對齊是有關(guān)結(jié)構(gòu)體內(nèi)容的很重要一個知識點,主要考察方式是計算結(jié)構(gòu)體的字節(jié)大小,所以本文就給大家詳細(xì)介紹一下C語言如何計算結(jié)構(gòu)體大小,文中的代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2023-07-07