时间:2022-08-26 09:11:28 | 栏目:C代码 | 点击:次
学习模板,首先我们需要了解一下什么是泛类编程
#include<iostream> using namespace std; int add(int a, int b) { return a + b; } double add(double a, double b) //这两个add构成了函数重载 { return a + b; } int main() { int a = 1; int b = 2; double c = 3; double d = 4; cout << add(a, b) << endl; cout << add(c, d) << endl; //假如我们想要实现不同类型变量的相加,可以创建不同的函数,构成函数重载来分别调用不同的函数 return 0; }
我们可以使用c++的函数重载来解决这个问题,但是函数重载本身就存在问题
1、函数重载仅仅类型不同,假如出现了新的类型,我们就需要重新写新的函数重载,代码的利用率低
2、代码可维护性低,一个出错可能会导致所有函数重载出错
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段
所以c++提供了一种模板来解决这个问题
模板本质上:本来应该由你写的代码,然后不想重复写,你给了一个模板,编译器通过模板,帮你生成了对应的代码
函数模板代表了一个函数家族,该函数模板与实参无关,当函数被使用时候会被实参初始化,从而产生不同的函数类型
函数模板的格式:
template<typename T1, typename T2, ......, typename Tn> //函数模板的参数不止一个,可以有很多参数 //返回值类型 函数名(参数列表) {}
函数模板的使用:
template<typename T> //也可以用<class T>,效果和<typename T>一样,但是不能用struct T add(T x, T y) { return x + y; }
注意:typename是函数模板的关键字,也可以使用class,但是不能使用struct
当我们用不同的参数使用函数模板时,就称为函数模板的初始化
函数模板的实例化有两种:
1、隐式实例化(让编译器根据实参推演模板参数的实际类型)
#include<iostream> using namespace std; template<typename T> T add(T x, T y) { return x + y; } int main() { int a = 1, b = 2; double c = 3, d = 4; cout << add(a, b) << endl; //使用了隐式实例化,由编译器自动推演实例化参数类型 return 0; }
2. 显式实例化(在函数名后的<>中指定模板参数的实际类型)
#include<iostream> using namespace std; template<typename T> T add(T x, T y) { return x + y; } int main() { int a = 1, b = 2; double c = 3, d = 4; cout << add<int>(a, c) << endl; //由于a和c的类型不同,所以我们必须使用显示实例化,即函数名后面<type>括号中加上你想要实例化的类型 return 0; }
1、模板模板可以和一个同名非函数模板同时存在
2、假如模板函数和非模板函数同名,编译器会选择一个更匹配的类型进行使用
#include<iostream> using namespace std; int add(int x, int y) { return x + y; } template<typename T> T add(T x, T y) { return x + y; } int main() { int a = 1, b = 2; double c = 3, d = 4; cout << add(a, b) << endl; //因为a,b是整型,所以会调用非函数模板,因为有都是整型参数的非函数模板 return 0; }
3、模板函数不允许自动类型转换,但普通函数可以进行自动类型转换
#include<iostream> using namespace std; template<typename T> T add(T x, T y) { return x + y; } int main() { int a = 1, b = 2; double c = 3, d = 4; cout << add(a, (int)c) << endl; return 0; }
假如我们要使用函数模板的add,需显示实例化add,或者将c强制类型转换,函数模板不会自动转换,因为他不知道要如何转换的
类模板的定义格式:
template<class T1, class T2, ..., class Tn> class 类模板名 { // 类内成员定义 };
template<class T> //创建类模板 class Date { public: void init(); private: int _year; }; template<class T> //假如我们需要在类模板的类外面定义函数,需要添加模板列表 Date<int>init() //还需要在类名后面<>中添加模板参数列表 { _year = 0; }
//Date是类名,Date<int>是类型 Date<int> d; //类模板的实例化需要在类模板名的后面<>中添加想要实例化的类型