C++自制心得——模板初步
我这里讲的模板比较基础,篇幅不长,后续会有模板的进阶内容
1. 函数模板
尽管我们在以前用函数重载解决了Swap函数的命名问题,但这样的方案存在缺陷,我们还是要为每个类型写一个对应Swap函数。除了类型不同, 这些Swap函数的逻辑完全一致,如果能实现类型的自动替换,那就能解放双手了,这就是泛型编程的逻辑
C++提供template(中文就叫模板)关键字实现泛型编程
其中的名字我们一般会用T系列表示,比方说T1, T2之类的,算是某种意义上的约定俗成
值得注意的是template定义的模板类型声明范围仅限它的下一个函数或类,出了范围即刻失效,不用担心多个模板情景下可能发生的模板类型重名问题(所以类模板的声明定义分离定义处需要额外声明一次模板)
这里问大家一个小问题,两个Swap语句调用的同一个Swap函数吗?
遇事不决,翻汇编代码


哦,的确不是同一个函数,不过,这两个长的很怪的函数是怎么出现的?


实际上,它们是模板函数Swap的对应实例化函数。因为根据模板函数推导出的不同类型函数其函数栈帧开辟大小不同,并且内部逻辑存在一定差别,因此编译器会提前推导并生成用到的实例化函数,而非想象中的实时推导
换句话说,泛型编程不会与我们想象的一样省略不同类型同一逻辑的函数,它只是把程序员的工作变成了编译器的工作(C和C++的编译器真是两个极端)
2. 类模板
除了函数模板,类也有模板,类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<> 中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。


现在我们用模板类的方式实现了存储不同类型的栈

类的声明定义如下
请不要将类模板声明定义放到不同的文件里,会出问题(模板进阶会讲)
3. 模板的实例化
模板实例化方式分隐式实例化和显式实例化
3.1 隐式实例化
隐式实例化就是让编译器自动推导类型

这里,编译器推导出的类型有int和double,但是模板只有一个参数,编译器不清楚用哪个类型实例化函数,结果就是报错
解决方案有两种,一种就是强制类型转换

同时,也可以选择显式实例化

3.2 显式实例化
在函数名后的<>中指定模板参数的实际类型
如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错
4. 模板参数的匹配原则
1. 一个非模板函数可以和一个同名的函数模板同时存在

2. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板


C++的基础部分总算讲了个七七八八,接下来就是C++中等难度的部分了------stl标准模板库,难度进一步升级,敬请期待