1. C++模板
-
思想:类型参数化,泛型编程,模板技术
-
写法:
template<class T>
或template<typename T>
//告诉编译器如果下面紧跟着的函数出现T不要报错,T是一个通用的类型void MySwap(T &a,T &b){}
MySwap(1,2)
//传入int a和int b后会进行自动类型推导,将T替换成int类型,以此类推MySwap<int>(a,b);
显示指定类型
-
模板函数与普通函数的区别:
-
模板函数的调用规则:
- 如果模板函数和普通函数重名(重载),优先调用普通函数;除非重载的普通函数没有实现体.
- 如果想强制调用模板,可以
MySwap<>(a,b);
- 如果模板函数可以产生更好的匹配,那么会优先调用模板函数.
2. 模板机制
- 函数模板通过具体类型产生不同的函数
- 编译器会对函数模板进行两次编译,再申明的地方对模板代码进行编译,在调用的地方对参数替换后的代码进行编译
3. 函数模板的局限性
- 函数模板的局限性:无法对数组和结构体进行部分操作;如果传入了数组,数组名为地址,因此它比较的是地址,而这也不是我们所希望的操作;
- 解决方法:第三代具体化自定义数据类型
- 语法:template<> 返回值 函数名<具体类型>(参数)
例如:
template<> bool MyCompare<Person>(Person &a,Person &b){
if(a.age==b.age){
return true;
}
return false;
}
4. 类模板
有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同。
与函数模板基本一致,不同点在template下定义的是类
- 类模板可以有默认参数
- 类模板不支持自动类型推导,必须显式指定类型
- 类模板中的成员函数创建时机:成员函数一开始不会创建出来,而是在运行时去创建.
- 类模板作函数参数:
(1)指定传入类型
void doWork(Person<string ,int> &p){//指定了类型
p.showPerson();
}
void test01(){
Person<string ,int> p("Tom",20);
doWork(p);//传入的类型与doWork指定的一样
}
(2)参数模板化
tips:使用typeid(T1).name()
查看类型
template<class T1,class T2> //函数模板
void doWork2(Person<T1,T2> &p){ //由传进的类型推导
//typeid(T1).name()
p.showPerson();
}
void test02(){
Person<string ,int> p("Tony",18);
doWork2(p);
}
(3) 整体类型化
template<class T> //只做了一个类的函数模板
void doWork3(T &p){ //将Person对象整体类型化,将整体的T进行推导成Person类型
p.showPerson();
}
void test03(){
Person<string ,int> p("Jack",15);
doWork3(p);
}
- 类模板作派生普通类
- 类模板类外实现成员函数:和普通的一样,加上作用域
template<class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age){}
- 类模板头文件和源文件分离实现会有些问题,建议不要写到头文件里.
5.类模板碰到继承的问题
类模板的子类叫做模板类.
Base类是类模板时,比如
template<class T>
class Base{
T age;
}
在Child类继承时必须告诉Base中的T类型,否则T无法分配内存
class Child:public Base<int>{}
6.类模板遇到友元函数
- 友元函数在类内实现
template<class T1, class T2>
class Person{
//1. 友元函数在类内实现
friend void PrintPerson(Person<T1, T2>& p){
_cout_ << "Name:" << p.mName << " Age:" << p.mAge << _endl_;
}
- 友元函数在类外实现
现在类内声明:friend void PrintPerson2<>(Person<T1, T2>& p);
再在类外实现:
//友元函数类外实现 加上<>空参数列表,告诉编译去匹配函数模板
template<class T1 , class T2>
void PrintPerson2(Person<T1, T2>& p)
{
_cout_ << "Name2:" << p.mName << " Age2:" << p.mAge << _endl_;
}