函数模板与类模板定义和使用

模板是将具有相似性的类和函数归纳起来构成一个类族或函数族,它可是程序具有通用性。模板分为类模板和函数模板。


目录

(一)函数模板

一般定义形式

模板函数重载

函数模板参数

带有多类型参数的函数模板

(二)类模板

类模板的使用


(一)函数模板

int max(int a,int b);
float max(float a,float b);
double max(double a,double b);

如上这三个重载函数,他们的操作相同,都是求两个数中的最大值。为了避免逐个定义重载函数的繁琐编程,由于函数模板使用通用数据类型定义函数,因此使用函数模板完成这项工作更为简洁和方便

一般定义形式

template<class T(类型参数表)>        //template函数模板关键字;T为通用数据类型
返回类型 FunctionName(数据参数表)     //FunctionName函数模板名
{
    函数模板定义体;                  //接上,T可为基本数据类型或类类型,需加前缀class和typename
}

例如对之前的三个重载函数进行模板化,为:

template<class T>
T max(T a,T b)
{
    return a>b?a:b;    //T作为返回类型和参数类型
}

函数模板只是函数的描述,表示它每次能单独处理类型形参表中说明的数据类型。它不是一个实实在在的函数,是以具体类型为实参来生成函数体的模板,编译系统不为其产生任何执行代码。使用函数模板可以根据特定的数据类型,产生一个该模板的实例,该函数可以像普通函数一样调用。

#include <iostream>

using namespace std;

template<class T>
T abs(T n)
{
	return (n<0)?-n:n;
}

int main()
{
	int int1 = 5;
	int int2 = -6;
	long lon1 = 70000L;
	long lon2 = -80000L;
	double dub1 = 9.95;
	double dub2 = -10.15;

	//模板函数的实例化
	cout<<"\nabs("<<int1<<")="<<abs(int1);		//abs<int>
	cout<<"\nabs("<<int2<<")="<<abs(int2);		//abs<int>
	cout<<"\nabs("<<lon1<<")="<<abs(lon1);		//abs<long>
	cout<<"\nabs("<<lon2<<")="<<abs(lon2);		//abs<long>
	cout<<"\nabs("<<dub1<<")="<<abs(dub1);		//abs<double>
	cout<<"\nabs("<<dub2<<")="<<abs(dub2);		//abs<double>
	cout<<endl;
	return 0;
}

结果
abs(5)=5
abs(-6)=6
abs(70000)=70000
abs(-80000)=80000
abs(9.95)=9.95
abs(-10.15)=10.15
请按任意键继续. . .

模板函数重载

在编译程序时,输入参数的类型与重载函数的参数类型隐式转换后一致时,调用重载函数,否则调用模板函数(由于博客和书的结论不太一样,并且不知道该听谁的,于是。。。自己总结了)

#include<iostream>
using namespace std;

template<typename T>
T Max(T a, T b) {
	cout << "\nT Max(T a,T b)" << endl;
	return a > b ? a : b;
}

int Max(int a, int b) {
	cout << "\nint Max(int a,int b)" << endl;
	return a > b ? a : b;
}

template<typename T>
T Max(T a, T b,T c) {
	cout << "\nT Max(T a,T b,T c)" << endl;
	return Max(Max(a, b), c);
}
int main() {
	int a = 1;
	int b = 2;
	cout << Max(a, b) << endl;           //当函数模板和普通函数模板都符合时,优先选择普通函数
	cout << Max<>(a, b) << endl;         //若显示使用函数模板,则使用<>类型列表
	cout << Max(3.0, 4.0) << endl;       //如果函数模板可以产生一个更好的匹配,则选择模板
	cout << Max(5.0, 6.0, 7.0) << endl;  //重载
	cout << Max('a', 100) << endl;       //调用普通函数可以隐式类型转换
	return 0;
}

结果
int Max(int a,int b)
2

T Max(T a,T b)
2

T Max(T a,T b)
4

T Max(T a,T b,T c)

T Max(T a,T b)

T Max(T a,T b)
7

int Max(int a,int b)
100
请按任意键继续. . .

函数模板参数

函数模板中的数据形参分为:

(1)引用型参数:可提高参数传递效率。

  • 一般引用型参数:template<class T>T max(T &a,T &b);      函数执行过程中,其数据形参的改变会影响数据实参的改变。
  • 常量引用型参数:template<class T>T max(const T &a,const T &b);        引用型参数前用 const 限定,最常使用(考虑参数传递效率和安全性)。

(2)非引用型参数: template<class T>T max(T a,T b);

带有多类型参数的函数模板

形式如下:

template<class T1,class T2,class T3...>
[return-type] function_name(T1 param1,T2 param2...);
//return-type 为返回类型,既可以是一个具体的类型,也可以是 T1、T2中的通用数据类型。

Template<class TRetun, class TArg>
TRetun max(TArg a,TArg b)
{
    return a > b ? a : b;
}
#include <iostream>

using namespace std;

template<class T1, class T2> void display(T1 x,T2 y)
{
	cout<<x<<" "<<y<<endl;
}

int main()
{
	char c = 'A';
	char str[] = "This is a test";
	int n = 10;
	float x = 1.5;
	double z = 3.1415926;
	//两个参数类型相同
	display(c, char(c + 2));
	display(str, str);
	display(n, 2 * n);
	display(x, 2 * x);
	display(z, 2 * z);
	cout<<"------------------------"<<endl;
	//两个参数类型不同
	display(c, str);
	display(str, c);
	display(n, str);
	display(str, 2 * x);
	display(z, n);

	return 0;
}

结果
A C
This is a test This is a test
10 20
1.5 3
3.14159 6.28319
------------------------
A This is a test
This is a test A
10 This is a test
This is a test 3
3.14159 10
请按任意键继续. . .

(二)类模板

使用模板生成对象时自动创建该模板的一个实例——模板类,也可以显式声明模板类。模板类主要用于容器类,这些类可以包含以特定方式组织起来的给定类型的对象集。例如数组、堆栈、链表,他们所使用的存储方式独立于操作对象的类型。类模板提供的工具,可以定义存储任意类型的对象的容器,模板的参数可用于指定容器存储的对象类型。

类模板定义及实现的一般形式如下:

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

定义和实现一个单向链表的模板类:

//list.h
#include <iostream>
using namespace std;

template<class T> class List
{
public:
	List();
	void Add(T&);					//添加结点
	void Remove(T&);				//删除结点
	T* Find(T&);					//查找结点
	void PrintList();				//打印链表
	~List();
protected:
	struct Node						//结构结点
	{
		Node* pNext;
		T* pT;
	};
	Node *pFirst;					//链首节点指针
};

template<class T>List<T>::List()
{
	pFirst = 0;
}

template<class T> void List<T>::Add(T& t)	//头插法
{
	Node* temp = new Node;			//从堆空间中申请一个结点
	temp->pT = &t;					//将T对象挂载在这个节点上
	temp->pNext = pFirst;			//将该结点指向链首的结点
	pFirst = temp;					//将该节点成为链首
}

template<class T> void List<T>::Remove(T& t)
{
	Node* q = 0;					//用来点位待删除的结点
	if(*(pFirst->pT)==t)			//T类中==需有定义
	{
		q = pFirst;
		pFirst = pFirst -> pNext;	//带删除结点在链首时的脱链
	}
	else
	{
		for(Node* p = pFirst; p -> pNext; p = p -> pNext)
		{
			if(*(p -> pNext -> pT) == t)
			{
				q = p -> pNext;
				p -> pNext = q -> pNext;	
				break;
			}
		}
	}
	if(q)
	{
		delete q -> pT;				//删除节点上的T类对象
		delete q;					//删除结点
	}
}

template<class T> T* List<T>::Find(T& t)
{
	for(Node* p = pFirst; p; p = p -> pNext)
		if(*(p -> pT) == t)
			return p -> pT;
	return 0;
}

template<class T> void List<T>::PrintList()
{
	for(Node* p = pFirst; p; p = p -> pNext)
		cout<<*(p -> pT)<<" ";
	cout<<endl;
}

template<class T> List<T>::~List()
{
	Node *p;
	while( p = pFirst )
	{
		pFirst = pFirst -> pNext;
		delete p -> pT;
		delete p;
	}
	pFirst = 0;
}

类模板的使用

类模板实例创建方式

className<类型实参表> object;

使用实例

// singleList.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include "list.h"
using namespace std;

int main()
{
	//创建模板类List<float>和该对象
	List<float> floatList;
	//创建和遍历浮点链表
	for(int i = 1; i < 7; i ++)
		floatList.Add(*new float(i + 0.6));
	floatList.PrintList();
	//查找并删除结点
	float b = 3.6;
	float* pa = floatList.Find(b);
	if(pa)
		floatList.Remove(*pa);
	floatList.PrintList();

	return 0;
}

结果
6.6 5.6 4.6 3.6 2.6 1.6
6.6 5.6 4.6 2.6 1.6
请按任意键继续. . .

 

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肥羊汤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值