栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

《C++》模板

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

《C++》模板

一、本章介绍

1、泛型编程

2、函数模板

3、类模板

二、泛型编程

什么是泛型编程?不知道你有没有经历这样的情景:你需要写一个交换函数,可以交换int、double、char、自定义类型。那么这对于C语言来说,就得专门写一个int交换函数、再写一个double交换函数、再写一个char交换函数。同时C语言还不支持重载,你还得写不一样的函数名。那如果我想写一个支持任意类型的交换函数,我们就不得不学习泛型编程。简单来说,泛型编程就是编写与类型无关的通用性代码,而模板就是泛型编程的基础。

三、函数模板

先写一个交换函数的模板

template
void Swap(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}

其中中的class可以换成typename,这两者在这里的使用没有区别,具体区别在迭代器那章会介绍。

需要注意的是,函数模板与具体的函数是有区别的,函数模板负责的是:你使用一个Swap(a,b),它就会实例化一份Swap(int& a,int& b)。同样的,你使用一个Swap(a,b),它就会实例化一份Swap(double& a,double& b),也就是说,编译器负责了跟多的工作,我们只需要传对应的参数,编译器就会依照函数模板自动实例化出你需要的函数。

3.1函数模板的实例化

函数模板的实例化分两种:

一、隐式实例化:让编译器根据实参推演模板参数的实际类型

template 
T Add(const T& left, const T& right) 
{
	return left + right;
}
int main()
{
	int a1 = 10, a2 = 20;
	double d1 = 10.0, d2 = 20.0;
	Add(a1, a2);
	Add(d1, d2);
	return 0;
}

 像普通函数一样使用,编译器会根据你传参的类型实例化出对应的函数。

如果传的类型有矛盾,编译器会报错,如下:

template 
T Add(const T& left, const T& right) 
{
	return left + right;
}
int main()
{
	int a1 = 10, a2 = 20;
	double d1 = 10.0, d2 = 20.0;
	Add(a1, d2);
	return 0;
}

 因为a1是int类型,d2是double类型,编译器无法推出T是什么类型,如果把T实例化为nt,那么d2传过来会发生隐式类型转换,编译器不允许这样的事情发生,因此直接报错。

解决办法1:

int main()
{
	int a1 = 10, a2 = 20;
	double d1 = 10.0, d2 = 20.0;
	Add(a1, (int)d2);
	return 0;
}

解决办法2:

使用显示实例化

int main()
{
	int a1 = 10, a2 = 20;
	double d1 = 10.0, d2 = 20.0;
	Add(a1, d2);
	return 0;
}
二、显式实例化:在函数名后的 <> 中指定模板参数的实际类型
int main() 
{
 int a = 1;
 double b = 1.1;
 Add(a, b);
 return 0; 
}
如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。 ~提问环节~ 问一: 如果同时存在普通函数和函数模板,使用时会选择哪个呢?
template 
void Add(const T& left, const T& right) 
{
	cout << "T Add(const T& left, const T& right)" << endl;
}

void Add(int& a, int& b)
{
	cout << "int Add(int& a, int& b)" << endl;
}

int main()
{
	int a = 0;
	int b = 5;
	Add(a, b);
	return 0;
}

 如果有现成的函数,编译器就不会实例化了,而是直接调用这个现成的函数。

问二: 下面这段代码,该输出什么?
template 
void Add(const T1& left, const T2& right) 
{
	cout << "void Add(const T1& left, const T2& right)" << endl;
}

void Add(int& a, int& b)
{
	cout << "int Add(int& a, int& b)" << endl;
}

int main()
{
	int a = 0;
	double b = 5.5;
	Add(a, b);
	return 0;
}

 

由于模板函数可以生成更加匹配的版本,因此编译器根据实参实例化出更加匹配的Add函数。

这里再次说明一下:模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

四、类模板 

我们用C语言写一个顺序表的时候,通常用改变typedef int DateType来改变存储的类型。

但如果我们想一个顺序表存int,另一个顺序表存double,这个时候我们就不得不写两个存不同类型的顺序表了,但这样写了太多重复的代码了,这对于代码人来说是不好忍受的。因此我们需要学习类模板,站在底层的角度就是让编译帮我们写重复的代码,我们只需要写一个类模板出来,想实例化存什么类型的类,直接用seqlist、seqlist即可。

4.1类模板的定义格式
template
class 类模板名
{
 // 类内成员定义
};
template
class Seqlist
{

public:
	Seqlist()
	{
		//构造函数
	}
	~Seqlist()
	{
		//析构函数
	}
private:
	T* _a;
	size_t _size;
	size_t _capacity;
};

int main()
{
	Seqlist s1;//存int的顺序表
	Seqlist s2;//存double的顺序表
	return 0;
}

需要注意的是Seqlist不是类型,因为它还没实例化,只能说是类名,Seqlist才是类型。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1019138.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号