嘉兴模板建站软件,seo兼职平台,qq邮箱怎么做网站,中国建筑网官网查询证书最近在看 C 的方法和类模板#xff0c;我就在想 C# 中也是有这个概念的#xff0c;不过叫法不一样#xff0c;人家叫模板#xff0c;我们叫泛型#xff0c;哈哈#xff0c;有点意思#xff0c;这一篇我们来聊聊它们底层是怎么玩的#xff1f;一#xff1a;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 getsumint(10, 10);long sum2 getsumlong(20, 20);printf(output: intsum%d, long: sum%ld, sum1, sum2);
}接下来我就很好奇这种玩法和 普通方法 调用有什么不同要想找到答案可以用 IDA 去看它的静态汇编代码。从静态反汇编代码看当前生成了两个函数符号分别为j_??$getsumHYAHHHZ 和 j_??$getsumJYAJJJZ现在我们就搞清楚了原来一旦给 模板 指定了具体类型它就生成了一个新的函数符号。乍一看这句话好像没什么问题但如果你心比较细的话会发现一个问题如果我调用两次 getsumint 方法那会生成两个具体函数吗为了寻找答案我们修改下代码int main() {int sum1 getsumint(10, 10);int sum2 getsumint(15, 15);
}然后再用 IDA 查看一下。哈哈可以发现这时候并没有生成一个新的函数符号其实往细处说j_??$getsumHYAHHHZ 是函数签名组合出来的名字因为它们签名一致所以在编译阶段必然就一个了。2. 类模板的玩法首先看下类模板的格式template typename T1, typename T2, … class className { };还是那句话开头一个 template 暴击告诉你这是一个模板 , 接下来上一段代码#include iostreamtemplate typename T class Calculator
{
public:T getsum(T a1, T b1) {return a1 b1;}
};int main() {Calculatorint cal1;int sum1 cal1.getsum(10, 10);Calculatorlong cal2;int sum2 cal2.getsum(15, 15);printf(output: sum1%d, sum2%ld, sum1,sum2);
}接下来直接看 IDA 生成的汇编代码。从上面的方法签名组织上看有点意思类名方法名 柔和到一个函数符号上去了可以看到符号不一样说明也是根据模板实例化出的两个方法。二C# 中的模板玩法 接下来我们看下 C# 中如何实现 getsum 方法当我把代码 copy 到 C# 中我发现不能实现简单的 泛型参数 加减乘除操作这就太搞了网上找了下实现方式当然也可以让 T 约束于 unmanaged那就变成指针玩法了。namespace ConsoleApp1
{internal class Program{static void Main(string[] args){Calculatorint calculator1 new Calculatorint();Calculatorlong calculator2 new Calculatorlong();int sum1 calculator1.getsum(10, 10);long sum2 calculator2.getsum(15, 15);Console.WriteLine($sum{sum1}, sum2{sum2});Console.ReadLine();}}public class CalculatorT 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);}}
}那怎么去看 Calculatorint 和 Calculatorlong 到底变成啥了呢大家应该知道C# 和 操作系统 隔了一层 C所以研究这种远离操作系统的语言还是有一点难度的不过既然隔了一层 C 那在 C 层面上必然会有所反应。如果你熟悉 CLR 的类型系统应该知道 C# 所有的 类 在其上都有一个 MethodTable 类来承载所以它就是鉴别我们是否生成多个个体的依据接下来我们用 WinDbg 查看托管堆看看在其上是如何呈现的。0:008 !dumpheap -stat
Statistics:MT Count TotalSize Class Name
00007ff9d37638e0 1 24 ConsoleApp1.Calculator1[[System.Int64, System.Private.CoreLib]]
00007ff9d3763800 1 24 ConsoleApp1.Calculator1[[System.Int32, System.Private.CoreLib]]从输出信息看C 层面变成了两个 methodtable 类如果不信的化还可以分别查看 mt 下的所有方法。0:008 !dumpmt -md 00007ff9d37638e0
MethodDesc TableEntry MethodDesc JIT Name
...
00007FF9D36924E8 00007ff9d37638d0 JIT ConsoleApp1.Calculator1[[System.Int64, System.Private.CoreLib]]..ctor()
00007FF9D36924E0 00007ff9d37638c0 JIT ConsoleApp1.Calculator1[[System.Int64, System.Private.CoreLib]].getsum(Int64, Int64)0:008 !dumpmt -md 00007ff9d3763800
--------------------------------------
MethodDesc TableEntry MethodDesc JIT Name
00007FF9D36924D0 00007ff9d37637f0 JIT ConsoleApp1.Calculator1[[System.Int32, System.Private.CoreLib]]..ctor()
00007FF9D36924C8 00007ff9d37637e0 JIT ConsoleApp1.Calculator1[[System.Int32, System.Private.CoreLib]].getsum(Int32, Int32)从输出信息看getsum(Int64, Int64) 和 getsum(Int32, Int32) 方法的入口地址 Entry 是完全不一样的所以它们是完全独立的个体。三总结 当看到 模板 和 泛型 两个词我感觉前者更 通俗易懂 一些当给模板赋予不同类型时将会生成新的实例在 C/C 中直接化为不同的函数符号在 C# 中会生成不同的 MethodTable由于 C# 远离机器 所以尽量谈到 C 层面即可