关于C++模板的一些知识总结

模板是一种静态多态的方式。当然还有一种就是函数重载,主要通过参数的个数、类型、顺序不同来体现重载,一种接口实现不同的功能。
重载注意点:返回值不能作为依据,const加在成员函数后面构成重载,const修饰的是this指针,代表函数不能修改成员变量。 const修饰参数的话如果是形参不构成重载,因为只是拷贝了一个值进去,体现不了const,如果是指针引用类型的话构成重载。

重载的缺陷:如果要定义不同的add方式,就要定义很多个add函数,参数不同,比较麻烦。使用模板就比较方便。
template add(T a,T b)只需要一个就够了。你可以发现,很多库STL,BOOST等,模板随处可见,所以了解它很重要的。

函数模板和类模板
template
void swap1(T &a,T &b)
{
T t=a;
a=b;
b=t;
}
template就是告诉编译器,我要泛型了,不要随便报错(会进行查找匹配)。调用的话就是
swap1(1,2);
当普通函数和模板函数同时存在的话,编译器会有限匹配普通函数,不行再匹配模板。(其中优先级全特化大于偏特化大于泛化)普通函数是一等公民,接下来是重载,再接下来是模板。
类模板一样,把成员函数用T表示。但是类模板有个独特的就是非类型参数。比如array<int,15> arr。15代表大小参数,就是非类型参数,和函数模板比的话泛化更强了。

全特化,偏特化(函数模板不能偏特化)
当某些类型需要特殊处理的话,就需要全特化了。(比如itertor需要允许用指针代替迭代对象,就需要特化了。)
template<> swap(int num1, double num2) 就是全特化,<>为空。
偏特化的话有两种形式,一个是某些特化某些不变。一个是加一些限制比如const,&,*等。
注意点:函数模板不能偏特化只能全特化。原因是因为重载可以实现函数偏特化的功能,所以其实只是编译器说不行。全特化其实也不会参与函数重载的解析。所以技术上来说是可以的,只是编译器不允许,减少不必要的负担。

模板的编译过程(为什么模板声明定义必须放在.h中)
模板和普通函数的组织过程不一样,需要注意。
模板两阶段编译。第一阶段是模板定义阶段,这个阶段不会检查类型参数,比如写错了,使用了不依赖于模板参数的符号等。第二是模板实例化阶段,这个阶段会检查类型参数。
引出一个问题,模板的声明和定义不能像普通函数一样,把声明放在头文件,定义放在源文件中。为什么?因为C++分离式编译的原理

C++采用分离式编译,优点是一个源文件调用另一个源文件时避免头文件的多次编译。所以分离式编译,把每个源文件单独编译,然后链接的时候和其他文件中的定义进行链接。

但是模板不行,我们要有这样一个观念,模板没有实例化之前,就是模板,不是任何的变量类型。这会导致其他文件的模板函数不会有具体实现,不会编译成具体的代码,进入不了符号表,导致链接的时候找不到。

解决这个问题的办法有三种
一个是包含模式,也就是常用的把模板定义和声明写在一起。主流的方式。缺点是如果模板很复杂,编译时间很长。
二是显示定义的方式,在函数前面加template func()。缺点是,如果有不同的类型,还得重新定义。
三是加export关键字,不过好像有的编译器并不支持,比如VS。

猜你喜欢

转载自blog.csdn.net/weixin_53344209/article/details/132282657