聊聊 C# 和 C++ 中的 泛型模板 底層玩法

最近在看 C++ 的方法和類模板,我就在想 C# 中也是有這個概念的,不過叫法不一樣,人家叫模板,我們叫泛型,哈哈,有點意思,這一篇我們來聊聊它們底層是怎么玩的?

一:C++ 中的模板玩法

畢竟 C++ 是兼容 C 語言,而 C 是過程式的玩法,所以 C++ 就出現了兩種模板類型,分別為:函數模板類模板,下面簡單分析一下。

1. 函數模板的玩法

玩之前先看看格式:template <typename T> rettype funcname (parameter list) { }

說實話,我感覺 C++ 這一點就做的非常好,人家在開頭就特別強調了,這是一個 template,大家不要搞錯了,按照這個格式,我們來一個簡單的 Sum 操作,參考代碼如下:

#include?<iostream>//求和函數
template?<typename?T>?T?getsum(T??t1,?T??t2)?{return?t1?+?t2;
}int?main()?{int?sum1?=?getsum<int>(10,?10);long?sum2?=?getsum<long>(20,?20);printf("output: int:sum=%d, long: sum=%ld",?sum1,?sum2);
}
88c48573b986301a1dbf315fc217313b.png

接下來我就很好奇,這種玩法和 普通方法 調用有什么不同,要想找到答案,可以用 IDA 去看它的靜態匯編代碼。

bd551d75d9cb6e4b6a86ee45cc65f931.png

從靜態反匯編代碼看,當前生成了兩個函數符號分別為:j_??$getsum@H@@YAHHH@Zj_??$getsum@J@@YAJJJ@Z,現在我們就搞清楚了,原來一旦給 模板 指定了具體類型,它就生成了一個新的函數符號。

乍一看這句話好像沒什么問題,但如果你心比較細的話,會發現一個問題,如果我調用兩次 getsum<int> 方法,那會生成兩個具體函數嗎?為了尋找答案,我們修改下代碼:

int?main()?{int?sum1?=?getsum<int>(10,?10);int?sum2?=?getsum<int>(15,?15);
}

然后再用 IDA 查看一下。

1bef085c0a3238da5235123d279d37e6.png

哈哈,可以發現這時候并沒有生成一個新的函數符號,其實往細處說:j_??$getsum@H@@YAHHH@Z ?是函數簽名組合出來的名字,因為它們簽名一致,所以在編譯階段必然就一個了。

2. 類模板的玩法

首先看下類模板的格式:template <typename T1, typename T2, …> class className { };

還是那句話,開頭一個 template 暴擊,告訴你這是一個模板 😄😄😄, 接下來上一段代碼:

#include?<iostream>template?<typename?T>?class?Calculator
{
public:T?getsum(T?a1,?T?b1)?{return?a1?+?b1;}
};int?main()?{Calculator<int>?cal1;int?sum1?=?cal1.getsum(10,?10);Calculator<long>?cal2;int?sum2?=?cal2.getsum(15,?15);printf("output:?sum1=%d,?sum2=%ld",?sum1,sum2);
}

接下來直接看 IDA 生成的匯編代碼。

6703c309bb5b7f376ea19c5fee8d9725.png

從上面的方法簽名組織上看,有點意思,類名+方法名 柔和到一個函數符號上去了,可以看到符號不一樣,說明也是根據模板實例化出的兩個方法。

二:C# 中的模板玩法

接下來我們看下 C# 中如何實現 getsum 方法,當我把代碼 copy 到 C# 中,我發現不能實現簡單的 泛型參數 加減乘除操作,這就太搞了,網上找了下實現方式,當然也可以讓 T 約束于 unmanaged,那就變成指針玩法了。

namespace?ConsoleApp1
{internal?class?Program{static?void?Main(string[]?args){Calculator<int>?calculator1?=?new?Calculator<int>();Calculator<long>?calculator2?=?new?Calculator<long>();int?sum1?=?calculator1.getsum(10,?10);long?sum2?=?calculator2.getsum(15,?15);Console.WriteLine($"sum={sum1},?sum2={sum2}");Console.ReadLine();}}public?class?Calculator<T>?where?T?:?struct,?IComparable{public?T?getsum(T?a1,?T?b1){if?(typeof(T)?==?typeof(int)){int?a?=?(int)Convert.ChangeType(a1,?typeof(int));int?b?=?(int)Convert.ChangeType(b1,?typeof(int));int?c?=?a?+?b;return?(T)Convert.ChangeType(c,?typeof(T));}else?if?(typeof(T)?==?typeof(float)){float?a?=?(float)Convert.ChangeType(a1,?typeof(float));float?b?=?(float)Convert.ChangeType(b1,?typeof(float));float?c?=?a?+?b;return?(T)Convert.ChangeType(c,?typeof(T));}else?if?(typeof(T)?==?typeof(double)){double?a?=?(double)Convert.ChangeType(a1,?typeof(double));double?b?=?(double)Convert.ChangeType(b1,?typeof(double));double?c?=?a?+?b;return?(T)Convert.ChangeType(c,?typeof(T));}else?if?(typeof(T)?==?typeof(decimal)){decimal?a?=?(decimal)Convert.ChangeType(a1,?typeof(decimal));decimal?b?=?(decimal)Convert.ChangeType(b1,?typeof(decimal));decimal?c?=?a?+?b;return?(T)Convert.ChangeType(c,?typeof(T));}return?default(T);}}
}

那怎么去看 Calculator<int>Calculator<long> 到底變成啥了呢?大家應該知道,C# 和 操作系統 隔了一層 C++,所以研究這種遠離操作系統的語言還是有一點難度的,不過既然隔了一層 C++ ,那在 C++ 層面上必然會有所反應。

如果你熟悉 CLR 的類型系統,應該知道 C# 所有的 類 在其上都有一個 MethodTable 類來承載,所以它就是鑒別我們是否生成多個個體的依據,接下來我們用 WinDbg 查看托管堆,看看在其上是如何呈現的。

0:008>?!dumpheap?-stat
Statistics:MT????Count????TotalSize?Class?Name
00007ff9d37638e0????????1???????????24?ConsoleApp1.Calculator`1[[System.Int64,?System.Private.CoreLib]]
00007ff9d3763800????????1???????????24?ConsoleApp1.Calculator`1[[System.Int32,?System.Private.CoreLib]]

從輸出信息看,C++ 層面變成了兩個 methodtable 類,如果不信的化,還可以分別查看 mt 下的所有方法。

0:008>?!dumpmt?-md?00007ff9d37638e0
MethodDesc?TableEntry???????MethodDesc????JIT?Name
...
00007FF9D36924E8?00007ff9d37638d0????JIT?ConsoleApp1.Calculator`1[[System.Int64,?System.Private.CoreLib]]..ctor()
00007FF9D36924E0?00007ff9d37638c0????JIT?ConsoleApp1.Calculator`1[[System.Int64,?System.Private.CoreLib]].getsum(Int64,?Int64)0:008>?!dumpmt?-md?00007ff9d3763800
--------------------------------------
MethodDesc?TableEntry???????MethodDesc????JIT?Name
00007FF9D36924D0?00007ff9d37637f0????JIT?ConsoleApp1.Calculator`1[[System.Int32,?System.Private.CoreLib]]..ctor()
00007FF9D36924C8?00007ff9d37637e0????JIT?ConsoleApp1.Calculator`1[[System.Int32,?System.Private.CoreLib]].getsum(Int32,?Int32)

從輸出信息看,getsum(Int64, Int64)getsum(Int32, Int32) 方法的入口地址 Entry 是完全不一樣的,所以它們是完全獨立的個體。

三:總結

當看到 模板泛型 兩個詞,我感覺前者更 通俗易懂 一些,當給模板賦予不同類型時將會生成新的實例,在 ?C/C++ 中直接化為不同的函數符號,在 C# 中會生成不同的 MethodTable,由于 C# 遠離機器, 所以盡量談到 C++ 層面即可 🤣🤣🤣

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

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

相關文章

ceph集群報 Monitor clock skew detected 錯誤問題排查,解決

ceph集群報 Monitor clock skew detected 錯誤問題排查&#xff0c;解決 告警信息如下&#xff1a; [rootceph-100-80 ceph]# ceph -w cluster ddc1b10b-6d1a-4ef9-8a01-d561512f3c1d health HEALTH_WARN clock skew detected on mon.ceph-100-81,…

Java實現畫八卦

八卦是由多個圓疊加而成&#xff0c;如果我們讓每個圓都有自己的顏色&#xff0c;那么具體結構便一目了然&#xff0c;如下圖所示&#xff1a; 顯然只要令對應的圓顏色相同&#xff0c;就能達到我們預期的效果。 用Java就能輕松畫出來&#xff1a; import java.awt.BasicStroke…

C語言試題四十五之把第1到第p個字符,平移到字符串的最后,把第p+1到最后的字符移到字符串的前部。

??個人主頁:個人主頁 ??系列專欄:C語言試題200例目錄 ??推薦一款刷算法、筆試、面經、拿大公司offer神器 ?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 請編寫一個…

【MATLAB統計分析與應用100例】案例006:matlab數據的標準化變換

文章目錄 1. 調用rand函數產生一個10行,4列的隨機矩陣,每列服從不同的均勻分布2. 調用zscore函數對x進行標準化變換(按列標準化),返回變換后矩陣xz,以及矩陣x各列的均值構成的向量mu,各列的標準差構成的向量sigma3. 變換結果1. 調用rand函數產生一個10行,4列的隨機矩陣…

十一、為影院添加影片制作準備服務《仿淘票票系統前后端完全制作(除支付外)》

一、為影院添加影片的邏輯和思考 首先打開在線編輯器進入我們的項目&#xff1a;https://editor.ivx.cn/ 進入之后找到上一節中制作的頁面&#xff0c;咱們設置點擊編輯按鈕后進入的頁面為影院添加影片頁&#xff1a; 接著咱們查看影院添加影片頁&#xff1a; 在該頁中&…

Linux 內核中斷內幕【轉】

轉自:http://www.ibm.com/developerworks/cn/linux/l-cn-linuxkernelint/ 本文對中斷系統進行了全面的分析與探討&#xff0c;主要包括中斷控制器、中斷分類、中斷親和力、中斷線程化與 SMP 中的中斷遷徙等。首先對中斷工作原理進行了簡要分析&#xff0c;接著詳細探討了中斷親…

SQL Server表分區

SQL Server表分區 什么是表分區 一般情況下&#xff0c;我們建立數據庫表時&#xff0c;表數據都存放在一個文件里。 但是如果是分區表的話&#xff0c;表數據就會按照你指定的規則分放到不同的文件里&#xff0c;把一個大的數據文件拆分為多個小文件&#xff0c;還可以把這…

apt 根據注解,編譯時生成代碼

apt&#xff1a; Retention后面的值&#xff0c;設置的為CLASS&#xff0c;說明就是編譯時動態處理的。一般這類注解會在編譯的時候&#xff0c;根據注解標識&#xff0c;動態生成一些類或者生成一些xml都可以&#xff0c;在運行時期&#xff0c;這類注解是沒有的~~會依靠動態生…

Web.config配置文件詳解(新手必看)

花了點時間整理了一下ASP.NET Web.config配置文件的基本使用方法。很適合新手參看&#xff0c;由于Web.config在使用很靈活&#xff0c;可以自定義一些節點。所以這里只介紹一些比較常用的節點。 <?xml version"1.0"?> <!--注意: 除了手動編輯此文件以外&…

Hello Playwright:(6)與元素交互

在上一節我們已經了解到如何定位到元素&#xff0c;那么接下來就可以與元素進行交互了。下面的例子都是以百度首頁作為測試頁面輸入文本FillAsync方法用于模擬用戶選中元素并輸入文本&#xff0c;這會觸發元素的 input 事件。該方法只適合<input>、<textarea>等可輸…

C語言試題四十六之將m行n列的二維數組中的字符數據,按列的順序依次放到一個字符串中。

??個人主頁:個人主頁 ??系列專欄:C語言試題200例目錄 ??推薦一款刷算法、筆試、面經、拿大公司offer神器 ?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 請編寫一個…

【MATLAB統計分析與應用100例】案例007:matlab數據的極差歸一化變換

文章目錄 1. 調用rand函數產生一個10行,4列的隨機矩陣,每列服從不同的均勻分布2. 調用rscore函數對x按列進行極差規格化變換, 返回變換后矩陣R,以及矩陣x各列的最小值構成的向量xmin,各列的極差構成的向量xrange1. 調用rand函數產生一個10行,4列的隨機矩陣,每列服從不同…

十二、動態座位響應及用戶訂票《仿淘票票系統前后端完全制作(除支付外)》

一、動態座位設置及發布 首先打開在線編輯器進入我們的項目&#xff1a;https://editor.ivx.cn/ 上一節中已經完成了座位設置的準備&#xff0c;這一節咱們將完成座位設置及發布的功能。 咱們首先給有座位設置事件&#xff1a; 有座位的事件設置當點擊后更改當前的內容為0即…

跨服務器 快速 導入數據表記錄 Insert into SELECT

Use DataBaseName/*開啟Ad Hoc Distributed Queries組件exec sp_configure show advanced options,1 reconfigure exec sp_configure Ad Hoc Distributed Queries,1 reconfigure*/Insert into tableName (col1&#xff0c;col2&#xff0c;col3&#xff0c;……) --字段不能含有…

C# 查詢大型數據集

LINQ 語法非常好&#xff0c;但其作用是什么&#xff1f;我們只要查看源數組&#xff0c;就可以看出需要的結果&#xff0c;為什么要查詢這種一眼就能看出結果的數據源呢&#xff1f;有時查詢的結果不那么明顯&#xff0c;在下面的示例中&#xff0c;就創建了一個非常大的數字數…

C語言試題四十七之程序定義了N×M的二維數組,并在主函數中自動賦值。請編寫函數function(int a[N][M], int m),該函數的功能是:將數組右上半三角元素中的值乘以m。

??個人主頁:個人主頁 ??系列專欄:C語言試題200例目錄 ??推薦一款刷算法、筆試、面經、拿大公司offer神器 ?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 程序定義了…

第六章 三大消息摘要算法總結

6.1、MD5 推薦使用CC&#xff08;即Commons Codec&#xff09;實現雖然已被破解&#xff0c;但是仍舊廣泛用于注冊登錄模塊與驗證下載的文件的完整性可以自己寫一個注冊登錄模塊&#xff1b;自己下載一個MD5加密的文件&#xff0c;然后通過之前編寫的工具類&#xff08;或者使用…

一、博客首頁搭建搭建《iVX低代碼仿CSDN個人博客制作》

制作iVX 低代碼項目需要進入在線IDE&#xff1a;https://editor.ivx.cn/ 一、頭部導航欄思路參考 首先我們可以查看CSDN的博客首頁&#xff0c;從中查看一下布局&#xff1a; 在以上首頁中&#xff0c;我們可以得知其頂部為一個整行&#xff0c;這個行內容左側為一個logo&am…

【MATLAB統計分析與應用100例】案例008:調用rand函數生成均勻分布隨機數

文章目錄 1. 生成隨機數分布直方圖2. 生成隨機數矩陣,服從均勻分布1. 生成隨機數分布直方圖 x = rand(10) % 生成10行10列的隨機數矩陣,其元素服從[0,1]上均勻分布 y = x(:)

linux samba服務器

本文轉自wanglm51051CTO博客&#xff0c;原文鏈接&#xff1a; http://blog.51cto.com/studyit2016/1890282&#xff0c;如需轉載請自行聯系原作者