免费做网页的网站,四川省建设招标网站,用照片做模板下载网站好,域名检测查询C模板详解 泛型编程函数模板函数模板的概念函数模板的原理 函数模板的实例化函数模板的匹配原则类模板类模板的定义格式类模板的实例化 泛型编程
如果让你编写一个函数#xff0c;用于两个数的交换。在C语言中#xff0c;我们会用如下方法#xff1a;
void Swapi(int* p1,… C模板详解 泛型编程函数模板函数模板的概念函数模板的原理 函数模板的实例化函数模板的匹配原则类模板类模板的定义格式类模板的实例化 泛型编程
如果让你编写一个函数用于两个数的交换。在C语言中我们会用如下方法
void Swapi(int* p1, int* p2)
{int tmp *p1;*p1 *p2;*p2 tmp;
}
// 交换两个双精度浮点型
void Swapd(double* p1, double* p2)
{double tmp *p1;*p1 *p2;*p2 tmp;
}因为C语言不支持函数重载所以用于交换不同类型变量的函数的函数名是不能相同的并且传参形式必须是址传递不能是值传递。
而在学习了C的函数重载和引用后我们又会用如下方法实现两个数的交换
// 交换两个整型
void Swap(int x, int y)
{int tmp x;x y;y tmp;
}
// 交换两个双精度浮点型
void Swap(double x, double y)
{double tmp x;x y;y tmp;
}
C的函数重载使得用于交换不同类型变量的函数可以拥有相同的函数名并且传参使用引用传参使得代码看起来不那么晦涩难懂。
但是这种代码仍然存在它的不足之处 1、重载的多个函数仅仅只是类型不同代码的复用率比较低只要出现新的类型需要交换就需要新增对应的重载函数。 2、代码的可维护性比较低其中一个重载函数出现错误可能意味着所有的重载函数都出现了错误。
那我们能否告诉编译器一个模子让编译器根据不同的类型利用该模子来生成相应的代码呢 就像做月饼的模子一样我们放入不同颜色的材料就能得到形状相同但颜色不同的月饼。 如果在C中也能够存在这样一个模具通过给这个模具填充不同颜色的材料(类型)从而得到形状相同但颜色不同的月饼(生成具体类型的代码)那将会大大减少代码的冗余。巧的是前人早已将树栽好我们只需在此乘凉。 泛型编程编写与类型无关的通用代码是代码复用的一种手段。模板是泛型编程的基础。
函数模板
函数模板的概念
函数模板代表了一个函数家族该函数模板与类型无关在使用时被参数化根据实参类型产生函数的特定类型版本。 函数模板的格式
templatetypename T1,typename T2,…,typename Tn
返回类型 函数名(参数列表)
{//函数体
}templatetypename T
void Swap(T x, T y)
{T tmp x;x y;y tmp;
}
注意typename是用来定义模板参数的关键字也可以用class代替但是不能用struct代替。
函数模板的原理
函数模板是一个蓝图它本身并不是函数。是编译器产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器。 在编译器编译阶段对于函数模板的使用编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如当用int类型使用函数模板时编译器通过对实参类型的推演将T确定为int类型然后产生一份专门处理int类型的代码对于double类型也是如此。
函数模板的实例化
用不同类型的参数使用模板时称为模板的实例化。模板实例化分为隐式实例化和显示实例化。 一、隐式实例化让编译器根据实参推演模板参数的实际类型
#include iostream
using namespace std;
templatetypename T
T Add(const T x, const T y)
{return x y;
}
int main()
{int a 10, b 20;int c Add(a, b); //编译器根据实参a和b推演出模板参数为int类型return 0;
}特别注意使用模板时编译器一般不会进行类型转换操作。所以以下代码将不能通过编译 int a 10;double b 1.1;int c Add(a, b);
因为在编译期间编译器根据实参推演模板参数的实际类型时根据实参a将T推演为int根据实参b将T推演为double但是模板参数列表中只有一个T编译器无法确定此处应该将T确定为int还是double。 此时我们有两种处理方式第一种就是我们在传参时将b强制转换为int类型第二种就是使用下面说到的显示实例化。 二、显示实例化在函数名后的中指定模板参数的实际类型
#include iostream
using namespace std;
templatetypename T
T Add(const T x, const T y)
{return x y;
}
int main()
{int a 10;double b 1.1;int c Addint(a, b); //指定模板参数的实际类型为intreturn 0;
}
**注意**使用显示实例化时如果传入的参数类型与模板参数类型不匹配编译器会尝试进行隐式类型转换如果无法转换成功则编译器将会报错。
函数模板的匹配原则
一、一个非模板函数可以和一个同名的函数模板同时存在而且该函数模板还可以被实例化为这个非模板函数
#include iostream
using namespace std;
//专门用于int类型加法的非模板函数
int Add(const int x, const int y)
{return x y;
}
//通用类型加法的函数模板
templatetypename T
T Add(const T x, const T y)
{return x y;
}
int main()
{int a 10, b 20;int c Add(a, b); //调用非模板函数编译器不需要实例化int d Addint(a, b); //调用编译器实例化的Add函数return 0;
}
二、对于非模板函数和同名的函数模板如果其他条件都相同在调用时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数那么选择模板
#include iostream
using namespace std;
//专门用于int类型加法的非模板函数
int Add(const int x, const int y)
{return x y;
}
//通用类型加法的函数模板
templatetypename T1, typename T2
T1 Add(const T1 x, const T2 y)
{return x y;
}
int main()
{int a Add(10, 20); //与非模板函数完全匹配不需要函数模板实例化int b Add(2.2, 2); //函数模板可以生成更加匹配的版本编译器会根据实参生成更加匹配的Add函数return 0;
}三、模板函数不允许自动类型转换但普通函数可以进行自动类型转换
#include iostream
using namespace std;
templatetypename T
T Add(const T x, const T y)
{return x y;
}
int main()
{int a Add(2, 2.2); //模板函数不允许自动类型转换不能通过编译return 0;
}
类模板
类模板的定义格式
templateclass T1,class T2,…,class Tn
class 类模板名
{//类内成员声明
};例如
templateclass T
class Score
{
public:void Print(){cout 数学: _Math endl;cout 语文: _Chinese endl;cout 英语: _English endl;}
private:T _Math;T _Chinese;T _English;
};注意类模板中的成员函数若是放在类外定义时需要加模板参数列表。
templateclass T
class Score
{
public:void Print();
private:T _Math;T _Chinese;T _English;
};
//类模板中的成员函数在类外定义需要加模板参数列表
templateclass T
void ScoreT::Print()
{cout 数学: _Math endl;cout 语文: _Chinese endl;cout 英语: _English endl;
}
除此之外类模板不支持分离编译即声明在xxx.h文件中而定义却在xxx.cpp文件中。
类模板的实例化
类模板实例化与函数模板实例化不同类模板实例化需要在类模板名字后面根然后将实例化的类型放在中即可。 //Score不是真正的类Scoreint和Scoredouble才是真正的类Scoreint s1;Scoredouble s2;