C++模板的概念 定义和使用

参考于《C++程序设计教程——设计实现与实现》

模板的概念:

若一个程序的功能是对某种特定的数据类型进行处理,则将所处理的数据类型说明为参数,就可以把这个程序改写成模板,模板可以让程序对任何其他数据类型进行同样方式的处理。
C++程序由类和函数组成,模板也分为类模板(class template)和函数模板(function template)。因此,可以使用一个带多种不同数据类型的函数和类,而不必在意数据类型的各种情况。

接下来,将分别介绍函数模板和类模板

函数模板:

函数模板的一般定义形式是:

template <类型形式参数>      //类型形式参数即此格式:<typename  形式参数>  或 <class 形式参数>
返回类型  函数名 (形式参数)
{
	//函数定义体;
}

注意:
其中的类型形式参数可以包含基本数据类型,也可以包含类的类型,如果是类类型,则需加前缀class。
typename(或class)是声明数据类型参数标识符的关键字,用以说明它后面的标识符是数据类型标识符。函数模板允许使用多个类型参数,但在template定义部分的每个形参前必须有关键字typename或class。
(在大多数情况下,typename与class是可以通用的,这里就不再详细说明)
这样的函数模板定义,并不是一个实实在在的函数,编译系统不为其产生任何执行代码。该定义只是对函数的描述,表示它每次能单独处理在类型形式参数中说明的数据类型。

当编译系统发现有一个函数调用:

 函数名 (实参)

系统将跟据实参中的类型,确认是否匹配函数模板中对应的形式参数,然后生成一个重载函数。该重载函数的定义体与函数模板的定义体相同,而形式参数的类型则是以实参的类型为基础,该重载函数称函数模板(template function)

——》函数模板与模板函数的区别:
函数模板是模板的定义,定义中的形式参数实际上是通用类型参数。
模板函数是实实在在的函数定义,它由编译系统在碰见具体的函数调用时所生成,具有程序代码。

函数模板例一:

#include<iostream>
using namespace std;

template<typename T> void swapa(T& a, T& b)   //将函数名命名为swapa是为了避免与内置函数作用重复
{
	T temp = a;
	a = b;
	b = temp;
	cout << "a = " <<a<<"    "<< "b = "<<b;
}

int main()
{
	int a = 5, b = 4;  //需要先定义a,b为int,不能直接传参数(5,4),因为是函数模板,计算机并不知道5,4是到底是什么类型(int? char? float?)
	swapa<int> (a,b);   //函数名 <类型> (形式参数)     需要指定参数类型为int,否则计算机不知道该使用何种类型  
	float c = 7.777, d = 2.333;
	swapa<float>(c,d);
}

运行结果:

a = 4    b = 5
a = 2.333    b = 7.777
请按任意键继续. . .

函数模板例二:
函数模板可将许多重载函数简单地归为一个:

#include<iostream>
using namespace std;

template<typename T> T max(T a, T b)   // T类型的max函数,实现重载函数。   这里typename也可换为class
{
	return a > b ? a : b;   //条件运算符  (条件表达式)?(条件为真时的表达式):(条件为假时的表达式)
}

int main()
{
	cout << "max(3,5) is " << max(3, 5) << endl;
	cout << "max('3','5') is " << max('3', '5') << endl;6
}

运行结果:

max(3,5) is 5
max('3','5') is 5
请按任意键继续. . .

当编译发现用指定数据类型调用函数模板时,就创建一个模板函数。
上例中,当编译程序发现max(3,5)调用时,它就产生了一个如下的函数定义,生成其程序代码:

int max(int a,int b)
{
return a > b ? a : b;
}

这时我们会发现一个问题:为什么例二不用像例一那样在使用时要声明类型什么?
我们可以将例一改为例二的格式:

#include<iostream>
using namespace std;

template<typename T> T swapa(T a, T b)     //注意之前的void swapa()改为了T wapa()
{
	T temp = a;
	a = b;
	b = temp;
	cout << "a = " << a << "    " << "b = " << b;
}

int main()
{
	swapa(5, 4); 
}

运行时即发现报错:

error C4716: “swapa<int>”: 必须返回一个值

从这个报错我们可以知道:
当使用函数模板重载函数时,系统会自动为其指定数据类型。
很明显,例二中的形式比例一更为方便,这样,实参是什么数据类型,返回值也是什么数据类型,不会出现前面的问题。而且模板又避免了相同操作的重载函数定义。

类模板:

类模板的一般说明形式是:

    template <类型形式参数>
    class 类名
    {
    	//类声明体;
    };
    
    template <类型形式参数>
    返回类型 类名 <类型> :: 成员函数名1(形式参数)
    {
    	//成员函数定义体;
    }

    ... ...
    template <类型形式参数>
    返回类型 类名 <类型> :: 函数名N(形式参数)
    {
		//成员函数定义体;
    }

其中的<类型形式参数>与函数,模板中的意义一样,即写为:<typename 形参> 或 <class 形参>
这样的一个说明(包括成员函数的定义),不是一个实实在在的类,而是对类的描述,称为类模板(class template)。
建立类模板之后,可以用下列方式创建类模板的实例:

类名  <类型实参>  该模板类的一个对象;

———》类模板与模板类的区别:
类模板是模板的定义,不是一个实实在在的类,定义中用到通用类型参数。
模板类是实实在在的类定义,是类模板的实例化。类定义中参数被实际类型所代替。

使用类模板的方法为:

  1. 在程序开始的头文件中说明类模板的定义。
  2. 在适当的地方,创建一个类模板的实例,编译发现正在创建一个类模板的对象时,便会创建该类模板的定义,同时,创建相应的对象实体。
  3. 有了对象名,以后的使用就和通常一样。但你规定了什么类型的模板类,在使用成员函数时,所赋的实参也要对应 该类型。

例:
这里我们建立一个RMB的类模板,该类可以实现对RMB对象的加add(),利息interest(),显示display()。该类的模板的定义如下rmb.h:

template <class T>    //template <类型形式参数>
class RMB
{
public:
	T add(T d);
	T interest(T rate); //计算利息
	void display()
	{
		cout << allmoney << endl;
	}
private:
	T allmoney=0;
};

template <class T>
T RMB<T>::add(T d)
{
	allmoney = allmoney + d;
	return allmoney;
}

template<class T>
T RMB<T>::interest(T rate)
{
	allmoney = allmoney + allmoney*rate;
	return allmoney;
}

主函数:

#include<iostream>
using namespace std;
#include"rmb.h"     //在程序开始的头文件中说明类模板的定义。

int main()
{
	RMB<double> money;   
	//创建一个类模板的实例,这里就指定了那个T指示为double类型
	//在应用程序中,编译发现RMB<double> money;   类似的声明时,要为其生成模板类的实实在在的定义,所以模板中必须包含整个模板(包括其成员函数定义)的完整定义,在生成模板类后,系统又为其创建该类的对象。
	
	double a = 26.86;    
	//需要先声明参数 为double
	//因为T RMB<T>::add(T d) 这里的T即是我们上面创建的double类型,它只接受double类型参数
	//这里的情况与上面函数模板的例一类似
	money.add(a);
	double b = 30.0;
	money.add(b);
	double rate = 0.14;
	money.interest(rate);
	money.display();
}

运行结果:

64.8204
请按任意键继续. . .

没了…
感谢某位不愿透露姓名的大佬对本次C++模板的指点

猜你喜欢

转载自blog.csdn.net/qq_28840013/article/details/84844300