聊聊 C++ 中的四種類型轉換符

一:背景

在玩 C 的時候,經常會用 void* 來指向一段內存地址開端,然后再將其強轉成尺度更小的 char*int* 來丈量一段內存,參考如下代碼:

int?main()
{void*?ptr?=?malloc(sizeof(int)?*?10);int*?int_ptr?=?(int*)ptr;char*?char_ptr?=?(char*)ptr;
}

由于 C 的自由度比較大,想怎么玩就怎么玩,帶來的弊端就是容易隱藏著一些不易發現的bug,歸根到底還是程序員的功底不扎實,C++ 設計者覺得不能把程序員想的太厲害,應該要力所能及的幫助程序員避掉一些不必要的潛在 bug,并且還要盡最大努力的避免對性能有過多的傷害,所以就出現了 4 個強制類型轉換運算符。

  1. const_cast

  2. reinterpret_cast

  3. dynamic_cast

  4. static_cast

既然 C++ 做了歸類,必然就有其各自用途,接下來我們逐一和大家聊一下。

二:理解四大運算符

1. const_cast

這是四個運算符中最好理解的,玩過 C++ 的都知道,默認情況下是不能修改一個 const 變量,比如下面這樣:

int?main()
{const?int?i?=?10;i?=?12;
}

這段代碼肯定是要報錯的,那如果我一定要實現這個功能,如何做呢?這就需要用到 const_cast 去掉它的常量符號,然后對 i 進行操作即可,所以修改代碼如下:

int?main()
{const?int?i?=?10;auto?j?=?const_cast<int*>(&i);*(j)?=?12;
}
d53640bebbada567e5c100b755b2f6e6.png

2. reinterpret_cast

從名字上看就是一個 重新解釋轉換,很顯然這個非常底層,如果大家玩過 windbg ,應該知道用 dt 命令可以將指定的內存地址按照某一個結構體丈量出來,比如說 C# 的 CLR 在觸發 GC 時,會有 gc_mechanisms 結構,參考代碼如下:

0:000>?dt?WKS::gc_mechanisms?0x7ffb6ba96e60
coreclr!WKS::gc_mechanisms+0x000?gc_index?????????:?1+0x008?condemned_generation?:?0n0+0x00c?promotion????????:?0n0+0x010?compaction???????:?0n1+0x014?loh_compaction???:?0n0+0x018?heap_expansion???:?0n0+0x01c?concurrent???????:?0+0x020?demotion?????????:?0n0+0x024?card_bundles?????:?0n1+0x028?gen0_reduction_count?:?0n0+0x02c?should_lock_elevation?:?0n0+0x030?elevation_locked_count?:?0n0+0x034?elevation_reduced?:?0n0+0x038?minimal_gc???????:?0n0+0x03c?reason???????????:?0?(?reason_alloc_soh?)+0x040?pause_mode???????:?1?(?pause_interactive?)+0x044?found_finalizers?:?0n0+0x048?background_p?????:?0n0+0x04c?b_state??????????:?0?(?bgc_not_in_process?)+0x050?allocations_allowed?:?0n1+0x054?stress_induced???:?0n0+0x058?entry_memory_load?:?0+0x05c?exit_memory_load?:?0

其實 reinterpret_cast 大概也是干這個事的,參考代碼如下:

typedef?struct?_Point?{int?x;int?y;
}?Point;int?main()
{Point?point?=?{?10,11?};//內存地址void*?ptr?=?&point;//根據內存地址?丈量出??PointPoint*?ptr_point?=?reinterpret_cast<Point*>(ptr);printf("x=%d",?ptr_point->x);
}

從代碼看,我直接根據 ptr 地址丈量出了 Point 結構,說實話這個和 C 玩法就比較類似了。

3. dynamic_cast

在多態場景下,有時候會遇到這樣的一個問題,一個父類有多個子類,我現在手擁一個父類,我不知道能不能將它轉換為其中一個子類,要試探一下看看,那怎么去試探呢?類似 C# 中的 as 運算符,在 C++ 中就需要用 dynamic_cast ?來做這件事情,參考如下:

//點
class?Point?{
public:Point(int?x,?int?y)?:x(x),?y(y)?{}virtual?void?show()?{}
public:int?x;int?y;
};//矩形
class?Rectangle?:public?Point?{
public:Rectangle(int?x,?int?y,?int?w,?int?h)?:?Point(x,?y),?w(w),?h(h)?{}
public:int?w;int?h;
};//三角形
class?Triangle?:public?Point?{
public:Triangle(int?x,?int?y,?int?z)?:Point(x,?y),?z(z)?{}
public:int?z;
};int?main()
{Point*?p1?=?new?Rectangle(10,?20,?100,?200);Point*?p2?=?new?Triangle(4,?5,?6);//將??p1?轉成?子類?Triangle?會報錯的Triangle*?t1?=?dynamic_cast<Triangle*>(p1);if?(t1?==?nullptr)?{printf("p1?不能轉成?Triangle");}
}
baa802fa7c2772a38d231434c21387d7.png

對,場景就是這個,p1 其實是 Rectangle 轉上去的, 這時候你肯定是不能將它向下轉成 Triangle , 問題就在這里,很多時候你并不知道此時的 p1 是哪一個子類。

接下來的一個問題是,C++ 并不像C# 有元數據,那它是如何鑒別呢?其實這用了 RTTI 技術,哪里能看出來呢?哈哈,看匯編啦。

Triangle*?t1?=?dynamic_cast<Triangle*>(p1);
00831D57??push????????0??
00831D59??push????????offset?Triangle?`RTTI?Type?Descriptor'?(083C150h)??
00831D5E??push????????offset?Point?`RTTI?Type?Descriptor'?(083C138h)??
00831D63??push????????0??
00831D65??mov?????????eax,dword?ptr?[p1]??
00831D68??push????????eax??
00831D69??call????????___RTDynamicCast?(083104Bh)??
00831D6E??add?????????esp,14h??
00831D71??mov?????????dword?ptr?[t1],eax

從匯編可以看到編譯器這是帶夾私貨了,在底層偷偷的調用了一個 ___RTDynamicCast 函數在運行時幫忙檢測的,根據 cdcel 調用協定,參數是從右到左,恢復成代碼大概是這樣。

___RTDynamicCast(&p1,?0,?&Point,?&Triangle,0)

3. static_cast

從名字上就能看出,這個強轉具有 static 語義,也就是 編譯階段 就生成好了,具體安全不安全,它就不管了,就拿上面的例子,將 dynamic_cast 改成 static_cast 看看有什么微妙的變化。

int?main()
{Point*?p1?=?new?Rectangle(10,?20,?100,?200);Point*?p2?=?new?Triangle(4,?5,?6);Triangle*?t1?=?static_cast<Triangle*>(p1);printf("x=%d,?y=%d,z=%d",?t1->x,?t1->y,?t1->z);
}
9ddff7f3cbecff716f4a286e9b3cccc5.png

我們發現居然轉成功了,而且 Triangle 的值也是莫名奇怪,直接取了 Rectangle 的前三個值,如果這是生產代碼,肯定要挨批了。。。

接下來簡單看下匯編代碼:

Triangle*?t1?=?static_cast<Triangle*>(p1);
00DF5B17??mov?????????eax,dword?ptr?[p1]??
00DF5B1A??mov?????????dword?ptr?[t1],eax??printf("x=%d,?y=%d,z=%d",?t1->x,?t1->y,?t1->z);
00DF5B1D??mov?????????eax,dword?ptr?[t1]??
00DF5B20??mov?????????ecx,dword?ptr?[eax+0Ch]??
00DF5B23??push????????ecx??
00DF5B24??mov?????????edx,dword?ptr?[t1]??
00DF5B27??mov?????????eax,dword?ptr?[edx+8]??
00DF5B2A??push????????eax??
00DF5B2B??mov?????????ecx,dword?ptr?[t1]??
00DF5B2E??mov?????????edx,dword?ptr?[ecx+4]??
00DF5B31??push????????edx??
00DF5B32??push????????offset?string?"x=%d,?y=%d,z=%d"?(0DF8C80h)??
00DF5B37??call????????_printf?(0DF145Bh)??
00DF5B3C??add?????????esp,10h

從代碼中看,它其實就是將 p1 的首地址給了 t1,然后依次把copy偏移值 +4,+8,+0C, 除了轉換這個,還可以做一些 int ,long ,double 之間的強轉,當然也是一樣,編譯時匯編代碼就已經生成好了。

好了,本篇就說這么多,希望對你有幫助。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/284799.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/284799.shtml
英文地址,請注明出處:http://en.pswp.cn/news/284799.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【QGIS入門實戰精品教程】3.1:QGIS如何連接SQL Server數據庫?

文章目錄 軟件必備測試SQL Server服務是否啟動QGIS與SQL Server建立連接軟件必備 SQL Server 2008 R2QGIS 3.22.3測試SQL Server服務是否啟動 打開SQL Server配置管理器,查看MSSQLSERVER服務的啟動情況。

開源重量級的流程引擎或UI引擎

關注這兩個方面的同學個踴躍加粉了~~同時在下面回復期望開源哪一個&#xff0c;將先開源呼聲高的一個。 好吧&#xff0c;先小秀一下UI&#xff1a; 增加下面的pom依賴&#xff0c;表示此工程需要org.tinygroup.aerowindow ?12345<dependency> <groupId>org.tinyg…

阿里云網盤內測開啟 填寫申請表獲取邀請碼 附最新申請地址

日前有相關報道顯示&#xff0c;阿里方面推出了一款名為“阿里云網盤”的獨立App&#xff0c;并且其是由阿里云團隊開發&#xff0c;定位則是為C端用戶提供可靠安全的存儲備份及智能相冊等功能。據了解&#xff0c;目前這款APP尚未正式上線&#xff0c;暫時還在邀請制測試階段。…

02 JRE與JDK

JRE (Java Runtime Environment) JAVA 運行環境 包括JAVA虛擬機和JAVA程序所需要的核心類庫&#xff0c;如查想要運行一個開發好的JAVA程序&#xff0c;計算機只需要安裝JRE即可 JDK&#xff08;JAVA Development Kit &#xff09;JAVA開發工具包 JDK是提供給JAVA開發人員使用…

第 133 章 FAQ

133.1. Haproxy 與 Nginx Haproxy 與 Nginx 都能實現負載均衡&#xff0c;那么 Haproxy 與 Nginx proxy 有什么差異&#xff0c;我們怎樣選擇兩種方案。 如果是用于 HTTP 負載均衡我建議使用 Nginx&#xff0c;它可以SSL證書掛載&#xff0c;緩存定制&#xff0c;實現各種復雜的…

跟我做?個?德地圖的 iOS / Android MAUI控件(Android 原?庫綁定)

我們已經介紹了如何通過 .NET 綁定 iOS 原?庫 &#xff0c;本篇開始介紹?下如何通過 .NET 綁定 Android 原?庫。Android的庫Android 的庫以 .jar 做打包&#xff0c; 通過?具你可以將多個 .jar 完成綁定&#xff0c;然后通過 C# 調?原?的 Java 庫。對?起 iOS &#xff0…

【QGIS入門實戰精品教程】4.6:QGIS實現柵格(影像、DEM)的拼接與掩膜提取

參考閱讀:ArcGIS實驗教程——實驗十一:影像拼接與提取 加載實驗數據 本實驗所采用的柵格數據為兩個dem數據和一個矢量范圍數據,加載如下圖所示: 柵格數據信息如下: 柵格拼接 點擊下拉菜單【柵格】→【雜項】→【合并(merge)】,如下所示:

ReSharper 2020.2 補丁

ReSharper 是一個JetBrains公司出品的著名的代碼生成工具。其能幫助Microsoft Visual Studio成為一個更佳的IDE&#xff0c;它包括一系列豐富的能大大增加C#和Visual Basic .net開發者生產力的特征。使用ReSharper&#xff0c;你可以進行深度代碼分析&#xff0c;智能代碼協助…

【轉】【公司調查】車來了APP

http://blog.sina.com.cn/s/blog_83b10acc0102vk7k.html【APP簡介】"車來了"是武漢元光科技有限公司開發的一款查詢公交車實時位置的手機軟件。不僅能提供公交車的到站距離、預計到站時間&#xff0c;還能顯示整條線路的實時通行狀況&#xff0c;讓人們不再盲目等待&…

零中頻接收機主要問題

直流偏差和本振泄漏問題基本不會影響超外差式接收機的性能&#xff0c;問題主要是鏡頻抑制。需要高Q值的帶通濾波器。 零中頻不存在鏡頻干擾&#xff0c;可以省掉鏡像抑制濾波器和中頻濾波器。零中頻的主要問題是&#xff1a;1直流偏差 2本振泄漏 3 閃爍噪聲。 1 本振泄漏 本振…

軍哥華為HCNP(科目H12-221)真題解析課程:1-30題

華為HCNP&#xff08;科目H12-221&#xff09;真題解析HCNP-R&S-IERS&#xff1a;(Huawei Certified Network Professional-Implementing Enterprise Routing and Switching Network)第1部分 如何參加HCNP考試1.1很簡單&#xff0c;華為HCNP即使沒有HCNA證書也可以考取&…

Blazor University (36)組件庫

原文鏈接&#xff1a;https://blazor-university.com/component-libraries/組件庫組件庫使我們能夠將組件和頁面以及任何支持文件&#xff08;例如 CSS 文件、JavaScript 和圖像&#xff09;打包到一個可重用的項目中。創建一個名為 ClassLibraryConsumer 的新 Blazor 解決方案…

【QGIS入門實戰精品教程】9.1:QGIS構建泰森多邊形(Thiessen Polygon)實例精解

泰森多邊形是進行快速插值和分析地理實體影響區域的常用工具。例如,用離散點的性質描述多邊形區域的性質,用離散點的數據計算泰森多邊形區域的數據。泰森多邊形可用于定性分析、統計分析和臨近分析等。 參考教程: ArcGIS構建泰森多邊形(Thiessen Polygon)實例精解 【Glob…

“Visual Studio 啟動不能打開上次打開的文件” 最正確的解決姿勢

網上很多提供的方法&#xff0c;不是刪除.vs目錄&#xff0c;就是修改.suo文件。 刪除有風險&#xff0c;操作需謹慎&#xff01;&#xff01; 其實最簡單的方法就是&#xff1a;工具——選項——項目和解決方案——?加載解決方案時重新打開文檔(D)

【QGIS入門實戰精品教程】5.1:QGIS地理坐標轉火星坐標系(GCJ02)案例教程

本文以案例的形式,講述WGS84(GPS)、火星坐標系(GCJ02)、百度地圖(BD09)坐標系之間互相轉換。 一、WGS轉火星坐標系對比 文中將行政區的WGS坐標轉為火星坐標系,局部效果對比: 二、火星坐標系簡介 火星坐標系統是一種國家保密插件,也叫做加密插件或者加偏或者SM模組,其…

spark streaming 的 Job創建、調度、提交

2019獨角獸企業重金招聘Python工程師標準>>> 上文已經從源碼分析了Receiver接收的數據交由BlockManager管理&#xff0c;整個數據接收流都已經運轉起來了&#xff0c;那么讓我們回到分析JobScheduler的博客中。 // JobScheduler.scala line 62def start(): Unit sy…

CSS屬性總結之background

最近在學習css3的一些新屬性&#xff0c;就把一些使用中遇到的方法和問題做一個小結。 background-color 背景顏色在IE7之前只顯示到padding區域&#xff0c;不包含border。而現代瀏覽器background-color都是從border的左上角&#xff0c;到border的右下角。 background-color:…

官宣!微軟發布 VS Code Server!

北京時間 2022 年 7 月 7 日&#xff0c;微軟在 VS Code 官方博客中宣布了 Visual Studio Code Server&#xff01;遠程開發的過去與未來2019 年&#xff0c;微軟發布了 VS Code Remote&#xff0c;開啟了遠程開發的新時代&#xff01;2020 年&#xff0c;微軟發布了 GitHub Co…

iis管理常用命令 創建IIS站點 應用應用程序 及虛擬目錄

::防止中文輸出亂碼 chcp 65001::臨時設置PATH set PATH%SystemRoot%\system32\inetsrv;%PATH% ::列出所有站點 appcmd list site::站點名稱 set sitename"WisdomEducation"::綁定域名和端口號 set domain"http/*:8080:,https/*:8443:"::網站源文件物理路徑…

【QGIS入門實戰精品教程】4.4:QGIS如何將點自動連成線、線生成多邊形?

個人簡介:劉一哥,多年研究地圖學、地理信息系統、遙感、攝影測量和GPS等應用,精通ArcGIS等軟件的應用,精通多門編程語言,擅長GIS二次開發和數據庫系統開發,具有豐富的行業經驗,致力于測繪、地信、數字城市、資源、環境、生態、國土空間規劃、空間數字建模、無人機等領域…