当前位置:   article > 正文

【C++】模版与泛型编程

【C++】模版与泛型编程

模版顾名思义,就好比模具,填充不同材料,获得不同材料制作的铸件。

泛型编程:是一种好的编程思想,是与类型无关的编程、代码复用的一种手段。

1. 函数模版

  概念:函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

  格式:template<typename T1, typename T2,......,typename Tn> typename是用来定义模板参数关键字,也可以使用class替换typename关键字。

Swap交换函数例子:

template<class T>
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在编译阶段,编译器根据传入的实参类型推演生成对应类型的函数。当然前提是T的类型是一致的,不能混搭:

int a = 1;
double d = 1.1;
Swap(a, d); // error
  • 1
  • 2
  • 3

注意类型隐式转换规则。

1.1 函数模板的实例化

  传入不同类型参数使用函数模板,称为函数模板的实例化。模板实例化分为:隐式实例化和显示实例化,准确地说是参数的实例化。

(1)隐式实例化:编译器根据实参推演模板参数的实际类型。

 以下传参调用编译不能通过,模板参数列表只有一个T,而传入的参数类型种类数量要多,编译器无法确定T的类型。

int a = 1;
double d = 1.1;
Swap(a, d); // error
  • 1
  • 2
  • 3

解决办法有强制转换或显示实例化,先说强制转换:

int a = 1;
double d = 1.1;
Swap(a, (int)d); // OK
  • 1
  • 2
  • 3

(2)显示实例化:调用函数时加<类型>指定参数类型。

int a = 1;
double d = 1.1;
Swap<int>(a, d); // OK
Swap<double>(a, d); // OK
  • 1
  • 2
  • 3
  • 4

1.2 函数模版与函数重载对比

使用函数重载也可以实现,但是代码量有点多:

void Swap(int& left, int& right)
{
	int temp = left;
	left = right;
	right = temp;
}

void Swap(double& left, double& right)
{
	double temp = left;
	left = right;
	right = temp;
}

void Swap(char& left, char& right)
{
	char temp = left;
	left = right;
	right = temp;
}

......
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

函数重载缺点:

  1. 函数重载仅参数类型不同,代码复用率比较低,新的参数类型出现,就需要增加一个重载的函数。
  2. 代码可维护性低。

模版本质是减少重复的工作,解放部分生产力,工业革命也是如此。函数模版不是函数!不是函数!不是函数!是编译器产生具体类型函数的模具,使用模板相当于我们把重复工作交给了编译器去做,去生成对应的函数。

1.3 函数模板其它规则

  (1)一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。如果调用函数时传参与非模板函数匹配,编译器不会去使用函数模板推演产生特定的函数实例,除非使用函数模板的显示实例化。比如:

void Swap(int& left, int& right)
{
	int temp = left;
	left = right;
	right = temp;
}

template<class T>
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

直接与非模板函数匹配:

int a = 1;
int b = 11;
Swap(a, b); 
  • 1
  • 2
  • 3

可以使用显示实例化与函数模板匹配,编译器去产生一个函数实例:

int a = 1;
int b = 11;
Swap<int>(a, b); 
  • 1
  • 2
  • 3

  (2)如果参数匹配,且存在这么一个匹配的非模板函数,优先调用它而不是函数模板产生的实例。

int Add(int left, int right)
{
	return left + right;
}

template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
	return left + right;
}

void Test() {
	Add(1, 2);  // 直接调用非模板函数
	Add(1, 2.0); // 调用函数模板实例化
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

2. 类模版

template<class T>
class MyStack {
private:
	T* data;
public:
	void push(T ele);
	T pop();
};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

同函数模板一样,类模板不是真正的类,需要进行类模板实例化。

Stack<int> stackInt;
Stack<double> stackInt;
  • 1
  • 2
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/831480
推荐阅读
相关标签
  

闽ICP备14008679号