.前言
C++中的模板分为函数模板和类模板。
在C++中,模板允许我们处理问题的逻辑从不同的数据类型中抽离出来,形成容器和算法。
当我们需要对某种数据进行存取和处理的时候,我们可以在程序中,选择合适的模板指定我们需要的数据类型,这个时候,编译器就会为我们生成适合这种类型的容器和算法函数。

.函数模板
1、情景
多个一样或几乎完全一样的重载函数体带来的问题不仅是冗余,还有就是当你打算修改算法的时候,如果你没有在各个函数体里进行同步修改的话,还会造成在同一系统中,处理同类型的问题,用的算法不一致,导致不一致性的问题。

2、例子
问题:整数类型和浮点数类型求绝对值的十分,需要写两种重载函数吗?

int abs(int x)
{
	return x < 0 ? -x : x;
}
double abs(double x)
{
	return x < 0 ? -x : x;
}
//两函数体相同,仅参数类型不同,产生冗余

解决办法:函数模板
功能:
(1)可用来创建动态增长和减小的数据结构
(2)它是类型无关的,因此具有很高的可复用性。
(3)它在编译时而不是运行时检查数据类型,保证了类型安全
(4)它是平台无关的,可移植性
(5)可用于基本数据类型

template<typename  T>
T abs(T x)
{
	return x < 0 ? -x : x;
}
//编译器根据实参类型,推导出类型(简单理解为在调用时用对应类型的标识符代替)

3、定义
函数模板不是一个实在的函数,编译器不能为其生成可执行代码。定义函数模板后只是一个对函数功能框架的描述,当它具体执行时,将根据传递的实际参数决定其功能。

4、格式
函数模板定义语法
.语法形式:
template<模板参数表>
函数定义
.模板参数表的内容
.类型参数:class(或typename)标识符
.常量参数:类型说明符 表示符
模板参数:template<参数表> class 标识符

.类模板
1、类模板的作用
使用类模板使用户可以为类声明一种模式,使得类中的某些数据成员、某些成员函数的参数、某些成员函数的返回值,能取任意类型(包括基本基本类型和用户自定义类型)

2、格式
类模板:

template<模板参数表>
class 类名
{
类成员声明
}

如果需要在类模板以外定义其函数,则要采取以下的形式:

template<模板参数表>
类型名 类名<模板参数标识符列表>::函数名(参数名)

例:

#include <iostream>
using namespace std;
struct Student
{
	int id;    //学号
	float gpa; //平均分
};

template<class T>
class Store//类模板:实现对任意数据进行存取
{
public:
	Store();
	T& getElem();              //提取数据函数
	void putElem(const T& x);  //存入数据函数
private:
	T item;                    //item用于存放任意类型的数据
	bool haveValue;            //haveValue标记item是否已被存入内容
};

//函数实现
//定义Store()
template <class T>
Store<T>::Store():haveValue(false){}
//定义getElem()
template <class T>
T& Store<T>::getElem()
{
	//如试图提取未初始化的数据,则终止程序
	if(!haveValue)
	{
		cout << "No item present!" << endl;
		exit(1);//使程序完全退出,返回操作系统
	}
	return item;     //返回item中存放的数据
}
template <class T>
void Store<T>::putElem(const T& x)
{
	//将haveValue置为true,表示item中已存入数值
	haveValue = true;
	item = x;        //将x值存入item
}


int main()
{
	Store<int> s1, s2;//此时整型int代替T,可简单理解为有个函数Store<数据类型>,会把之前暂未定义的数据类型给替代为<>中的数据类型
	s1.putElem(3);
	s2.putElem(-7);
	cout << s1.getElem() << " " << s2.getElem() << endl;

	Student g = { 1000,23 };
	Store<Student> s3;
	s3.putElem(g);
	cout << "The student id is" << s3.getElem().id << endl;//s3.getElem返回了Student类型

	Store<double> d;
	cout << "Retrieving object D...";
	cout << d.getElem() << endl;
	//d未初始化,执行函数D.getElement()时导致程序终止
	
	return 0;
}

结果为:

3 -7
The student id is1000
Retrieving object D...No item present!

注:
c++模板类/模板函数的声明与定义应该放在头文件里,不要分开来写类中函数的声明与定义(比如在.H文件里声明某个成员函数,在.CPP文件里定义该成员函数),这样会导致连接错误。所应该将模板类/模板函数的定义与声明写在一个.h文件里。(如果你用VS给的提示也是让你在头文件定义)

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐