目录
泛型编程
所谓泛型编程就是独立于任何特定类型的方式编写代码,使用泛型程序时,需要提供具体陈旭实例所操作的类型或者值。我们经常用到STL容器、迭代器、和算法都是泛型编程的例子
在C语言阶段,要实现一个通用的交换函数我们只能通过定义对应不同参数类型的多个函数来实现,而且各函数的函数名不能相同,比如 Swapi、Swapd、Swapc;到了C++阶段我们可以通过函数重载来定义多个参数类型不同但函数名相同的函数来实现,但是函数重载有以下几个缺陷:
- 重载的函数仅仅是参数类型不同,代码复用率比较低,并且只要有新类型出现时,就需要用户自己增加对应的函数
- 代码的可维护性比较低,一个出错可能所有的重载均出错
- 模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型;
- 模板是一种对类型进行参数化的工具;
- 通常有两种形式:函数模板和类模板;
- 函数模板针对仅参数类型不同的函数;
- 类模板针对仅数据成员和成员函数类型不同的类;
- 使用模板的目的就是能够让程序员编写与类型无关的代码。比如编写了一个交换两个整型int 类型的swap函数,这个函数就只能实现int 型,对double,字符这些类型无法实现,要实现这些类型的交换就要重新编写另一个swap函数。使用模板的目的就是要让这程序的实现与类型无关,比如一个swap模板函数,即可以实现int 型,又可以实现double型的交换。
函数模板
函数模板概念
值和类型是数据的两个主要特征,它们在C++中都可以被参数化。
数据的值可以通过函数参数传递,在函数定义时数据的值是未知的,只有等到函数调用时接收了实参才能确定其值。——这就是值的参数化。
数据的类型也可以通过参数来传递,在函数定义时可以不指明具体的数据类型,当函数 调用时,编译器根据传入的实参自动推断数据类型。——这就是类型的参数化(把类型 定义为参数)
带有类型参数的一段代码,实际上代表了一类代码,可以实现代码的复用,常用模板来实现。
模板——是一段带有类型参数的程序代码,可以通过给这些参数提供一些类型来得到针对不同类型的具体代码。
模板是C++中支持泛型编程的重要方法,是实现代码复用的工具,是实现参数化多态(类型参数化)的手段,减轻了编程及维护的工作量和难度。
一个模板并非一个实实在在的类或函数,仅仅是一个类或函数的描述。模板是规则,通过模板可以演化出多个具体的类或函数。
在C++中,能带有类型参数的代码可以是函数和类,所以模板一般分为函数模板和类模板。
函数模板格式
template <typename 形参名, typename 形参名...> //模板头(模板说明)
返回值类型 函数名(参数列表) //函数定义
{
函数体;
}
template<typename T>
void Swap( T& left, T& right)
{
T temp = left;
left = right;
right = temp;
}
- template是声明模板的关键字,告诉编译器开始泛型编程。
- 尖括号<>中的typename是定义形参的关键字,用来说明其后的形参名为类型参数,(模板形参)。Typename(建议用)可以用class关键字代替,两者没有区别。
- 模板形参(类属参数)不能为空(俗成约定用一个大写英文字母表示),且在函数定义部分的参数列表中至少出现一次。与函数形参类似,可以用在函数定义的各个位置:返回值、形参列表和函数体。
- 函数定义部分:与普通函数定义方式相同,只是参数列表中的数据类型要使用尖括号<>中的模板形参名来说明。当然也可以使用一般的类型参数。
函数模板的原理
#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;
}
当调用add()函数传入int型参数12和参数34时,形参T被替换成int,得到结果 为46
当传入float型参数12.2和参数45.6时,形参T被替换成float,得到结果为57.8
避免了为int型定义一个求和函数,再为float型定义一个求和函数,实现了代码复用。
利用模板实现了不同类型的变量相加,可以发现利用模板的话大大减少了代码量,提高了代码复用性。
需要注意的是:
对函数模板的调用应使用实参推演来进行。
add(2,3)或 int a=2,b=3; add(a,b)
编译器会根据传入的实际参数2、3推演出传入的是int类型参数,则T为int类型
add(int, int) //错,不能在函数调用的参数中指定模板形参的类型来直接将类型传入