目录
一、什么是c++的模板
二、模板的概念
三、函数模板
(1)什么是函数模板
(2)函数模板的定义格式
(3)案例
(4)函数模板的实例化
a.实例化
b.显式实例化
(5)函数模板的重载
(6)使用函数模板要注意的问题
四、类模板
1、定义类模板的格式
2、类与类模板的关系
3、类模板的实例化
(1)使用类模板创建对象时,必须指明具体的数据类型。
(2)当类模板有两个模板形参时,创建对象时,类型之间要用逗号分隔开。
(3)可以使用对象指针的方式来实例化
一、什么是c++的模板
程序设计中经常会用到一些程序实体:它们的实现和所完成的功能基本相同,不同的仅 仅是所涉及的数据类型不同。而模板正是一种专门处理不同数据类型的机制。
模板是泛型程序设计的基础(泛型generic type——通用类型之意)。
二、模板的概念
值和类型是数据的两个主要特征,它们在C++中都可以被参数化。
数据的值可以通过函数参数传递,在函数定义时数据的值是未知的,只有等到函数调用 时接收了实参才能确定其值。——这就是值的参数化。
数据的类型也可以通过参数来传递,在函数定义时可以不指明具体的数据类型,当函数 调用时,编译器根据传入的实参自动推断数据类型。——这就是类型的参数化(把类型 定义为参数)
带有类型参数的一段代码,实际上代表了一类代码,可以实现代码的复用,常用模板来 实现。
模板——是一段带有类型参数的程序代码,可以通过给这些参数提供一些类型来得到针 对不同类型的具体代码。
在C++中,能带有类型参数的代码可以是函数和类,所以模板一般分为函数模板和类模 板。
三、函数模板
(1)什么是函数模板
函数模板——实际上是定义一个通用函数,它所用到的数据的类型(包括返回值类 型、形参类型、局部变量类型)均被作为参数:不指定具体类型,而是用一个虚拟 的类型来代替(实际上是用一个标识符来占位)。凡是函数体相同的函数都可以用 这个模板来代替,在函数调用时根据传入的实参来逆推出真正的类型。这个通用函 数就称为函数模板。
(2)函数模板的定义格式
template <typename 形参名, typename 形参名...> //模板头(模板说明)
返回值类型 函数名(参数列表) //函数定义
{
函数体;
}
注意注意:
1,template是声明模板的关键字,告诉编译器开始泛型编程。
2,尖括号<>中的typename是定义形参的关键字,用来说明其后的形参名为类型 参数,(模板形参)。Typename(建议用)可以用class关键字代替,两者没有区别。
3,模板形参(类属参数)不能为空(俗成约定用一个大写英文字母表示),且在函 数定义部分的参数列表中至少出现一次。与函数形参类似,可以用在函数定义的各 个位置:返回值、形参列表和函数体。
4,函数定义部分:与普通函数定义方式相同,只是参数列表中的数据类型要使用 尖括,号<>中的模板形参名来说明。当然也可以使用一般的类型参数。
(3)案例
用函数模板实现多种类型数据的相加
#include <iostream>
using namespace std;
template<typename T>//模板头,template关键字告诉编译器开始泛型编程
T add(T t1, T t2)//类型参数化为T
{
return t1 + t2;
}
int main()
{
cout << add(12, 34) << endl;
cout << add(12.2,45.6) << endl;
return 0;
}
输出结果:
46
57.8
当调用add()函数传入int型参数12和参数34时,形参T被替换成int,得到结果 为46
当传入float型参数12.2和参数45.6时,形参T被替换成float,得到结果为57.8
避免了为int型定义一个求和函数,再为float型定义一个求和函数,实现了代码 复用。
(4)函数模板的实例化
函数模板实例化的方法有两种:
隐式实例化:根据具体的函数调用形式,推演出模板参数类型。
显式实例化:通过显式声明形式指定模板参数类型
(1)隐式实例化
根据函数调用时传入的数据类型,推演出模板形参类型。模板形参的类型是隐 式确定的。
比如上面的多种类型相加
第一次调用add()函数模板:add(12,34),
①编译器根据传入的实参(12和34—>int型),推演出模板形参类型是int
②会将函数模板实例化出一个int类型的函数:
int add(int t1, int t2)
{
return t1 + t2;
}
③生成int类型的函数后,再将实参12和34传入进行运算。
第二次调用add()函数模板:add(12.2, 45.6)
实参为float类型的数据,编译器先将模板实例化为如下模板函数后,再将实 参12.2和45.6传入进行运算:
float add(float t1, float t2)
{
return t1 + t2;
}
(2)显式实例化
template 函数返回值类型 函数名<实例化的类型>(参数列表);
注意:这是声明语句,要以分号结束,<>中是显式实例的数据类型,即要实例 化出一个什么类型的函数。如:显示实例化为int,则在调用时,不是int 类 型的数据会 转换为int类型进行计算。
(5)函数模板的重载
前面学习过函数的重载。而函数模板可以用来创建一个通用功能的函数,以支持多 种不同形参,不同类型的参数调用,就产生一系列重载函数。
比如定义一个两个数相加的模板
根据传入参数不同,会实例化出不同的函数,比如
template<typename T>
T add(T t1, T t2)
{
return t1 + t2;
}
(6)使用函数模板要注意的问题
函数模板中的每一个类型参数在函数参数表中必须至少使用一次。例如:下 面的函数模板声明是不正确的:函数模板声明了两个参数T1与T2,但在使用 时 只使用了T1,没使用T2。
在全局域中声明的与模板参数同名的对象、函数或类型,在函数模板中将被 隐藏。例如:在函数体内访问num是访问的T类型的num,而不是全局变量num
int num;
template <typename T>
void func(T t)
{
T num;
}
四、类模板
1、定义类模板的格式
template<typename 形参名,typename 形参名…>
class 类名
{
………
}
注意:
说明:
(1)类模板中的关键字含义与函数模板相同。
(2)类模板中的类型参数可用在类声明和类实现中。类模板的模板形参(类型参 数)不能为空,一旦声明了类模板就可以用类模板的形参名声明类中的成员变量和 成员函数,即在类中使用内置数据类型的地方都可以使用模板形参名来代替。
template<typename T> //这里不能有分号。一个模板形参
class A
{
public:
T a; //成员变量
T b; //成员变量
T func(T a, T b); //成员函数声明
};
2、类与类模板的关系
由于类模板包含类型参数,因此也称为参数化类,如果说类是对象的抽象,对象是 类的实例,则类模板是类的抽象,类是类模板的实例。
3、类模板的实例化
定义了类模板后就要使用类模板创建对象以及实现类中的成员函数,这个过程其实 也是类模板实例化的过程,实例化出的具体类称为模板类。
(1)使用类模板创建对象时,必须指明具体的数据类型。
例如:用上述定义的模板类A创建对象,则在类A后面跟<>,并在里面表明相应 的类型:
A<int> a; //类A中凡是用到模板形参的地方都会被int类型所代替
强调:与函数模板不同的是,类模板在实例化时,必须在尖括号中为模板形参显式 地指明数据类型(实参),编译器不能根据给定的数据推演出数据类型。即:不存 在将整型值10推演为int类型传递给模板形参的实参推演过程,必须要在<>中指 定int类型。
(2)当类模板有两个模板形参时,创建对象时,类型之间要用逗号分隔开。
(3)可以使用对象指针的方式来实例化