探索C嘎嘎:模版初阶

时间:2024-10-21 20:03:20

前言:


目录

1.泛型编程

1.1.引子

1.2.泛型编程

2.函数模版

2.1.函数模版的概念

2.2.函数模版的格式

2.3.函数模版的原理

2.4.函数模版的实例化

 2.4.1.隐式实例化

2.4.2.显示实例化

2.5.函数模版的匹配原则

3.类模版

3.1.类模版的定义格式

3.2.类模版的实例化

4.总结
​​​​​​​


正文:

1.泛型编程

1.1.引子

void swap(int& a, int& b)
{
	int c = a;
	a = b;
	b = c;
}
void swap(float& a, float& b)
{
	float c = a;
	a = b;
	b = c;
}
void swap(char& a, char& b)
{
	char c = a;
	a = b;
	b = c;
}

  当我们在写一个项目的时候,那个项目既有整形的交换,浮点型的交换,字符型交换等等,这就意味着我们需要写三个重载的函数来完成交换函数,这样就体现不出来C++的简介美了,只会让我们增加写代码的量,而且还有代码的可维护性比较低,一步错步步错,这就得不偿失了,于是C++就推出了一个好用的功能,它就是模版,通过写模版我们就可以实现出交换函数,一个模版便可以解决上面三个函数的问题2,在具体讲解模版之前,小编先给各地读者朋友简单介绍一下泛型编程。

1.2.泛型编程

2.函数模版

2.1.函数模版的概念

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

2.2.函数模版的格式

template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表){}  //这里需要注意,此时上面的typename也可以写成class,怎么方便怎么来
template<class T>
void swap(T& x, T& y)
{
	T m = x;
	x = y;
	y = m;
}

2.3.函数模版的原理

  函数模版其实和现实生活中的蓝图差不多,它本身并不是函数,是编译器用使用方式产生特定的具体类型的模具,所以其实模版就是帮助我们把本来我们自己要重复干的活交给了编译器来做,简单来说,我们通过模版让编译器变成了牛马,其中的过程如下图所示:

2.4.函数模版的实例化

  用不同的类型使用函数模版的时候,称为函数模版的实例化,函数模版的实例化可以分为隐式实例化和显示实例化,现在我们先来进行前者的讲述。

 2.4.1.隐式实例化
template<class T>
T Add(T x, T y)
{
	return x + y;
}
int main()
{
	int a = 12, b = 13;
	double c = 11.1, d = 12.2;
	int m = Add(a,b);
	Add(c, d);
}

  以上就是函数模版的隐式实例化,其实隐式实例化可以理解为我们什么也不需要做,让编译器帮我们去做就好了,不过此时的隐式实例化有一个情况倘若我们什么也不做是行不通的,就比如下面的实例化:

Add(a, d);

   此时如果这么写的话编译器是给我们报错的,编译器报错的原因解释的不太行,这里小编提一嘴,报错后编译器给出的错误并不是完全正确的,有时候也是会有出错的情况,这里出错的原因其实就是此时的编译器是无法理解此时我们传的类型到底是什么,如果是按照第一个参数来断定T的类型,那么在第二个参数的时候便会出错,这让编译器摸不着头脑了,对于这个问题的解决策略,小编有两种解法可以帮助我们去把这个题目解决,如下所示:

1.把某一个元素强制类型转换(简单粗暴)

Add(a, (int)d);

2. 再写一个模版,不过此时的模版参数是两个,如下所示:

template<class T1,class T2>
T1 Add(T1 x, T2 y)
{
	return x + y;
}
2.4.2.显示实例化

  对于显示实例化,它的用法也是很简单,我们仅需在函数名后加上<>即可,<>里面放置的是我们想要模版参数类型的实际类型,还是拿上面的整形和浮点型相加来进行举例,如果我们仅写一个模版参量的模版,那么强制类型转换是第一种解决方案,显示实例化则是第二种解决方案,如下所示:

Add<int>(a, d);

  上面的代码就可以成功的去运行,因为此时我们使用了显示实例化,我们直接告诉了编译器,此时的模版参量就是int类型,编译器会在传参的过程中默默会生成隐式类型转换,把其中不是整形的转换为整形的,这就是显示类型实例化,难度也没有很大,各位读者朋友要知道这些实例化的方法,避免以后框框出错,下面我们进入函数模版最后一部分的讲解。

2.5.函数模版的匹配原则

int Add(int x, int y)
{
	return x = y;
}
template<class T>
T Add(T x, T y)
{
	return x + y;
}
int main()
{
	int a = 12, b = 13;
	Add(a, b);
}

  上图就显示了编译器是会调用现成的函数的,这就引出了第二个特点:

 2.对于非模版函数和同名函数模版,如果其他条件都相同,在调用时会优先调用非模版函数而不会从该模版产生出一个实例,如果模版可以产生一个具有更好匹配的函数,那么还是会选择模版。这个特点小编也在前面说了,编译器又不是*,它虽然是一个牛马,但它知道如何做才会省事,所以它是会筛选模版函数的,就比如我写了两个模版参量的模版和一个模版参量的模版,如果我用了Add(1,2),那么是会去调用一个参量的,因为省事,但是如果我是Add(1,1.1),那么系统会直接调用两个模版参量的,如下所示:

template<class T>
T Add(T x, T y)
{
	return x + y;
}
template<class T1,class T2>
T1 Add(T1 x, T2 y)
{
	return x + y;
}
int main()
{
	int a = 12, b = 13;
	double c = 11.1, d = 12.2;
	Add(a, b);
	Add(a, d);
}

  上面的调试过程便给我们展示了函数模版是如何去进行调用的,如果都是一个类型,编译器是会调用单模版参量的模版,因为省事,仅需把一个T转换为一个类型即可;如果有两个类型,那么自然的就会去调用两个模版参量的模版,这就是第二个匹配原则,下面来看第三个:

3.类模版

3.1.类模版的定义格式

template<class T1,class T2>  //不一定就这些
class wang
{
	//类内成员函数的定义或者类内成员的定义
};
template<class T>
class Stack
{
public:
	Stack(int capcaity = 4)
	{
		_arr = new Stack[capcaity];
		_size = 0;
		_capcaity = capcaity;
	}
private:
	T* _arr;
	int _capcaity;
	int _size;
};

3.2.类模版的实例化

int main()
{
	Stack<int>s1; //这样实例化可以额
	Stack s2;  //这样实例化会报错,报错原因:缺少 类模板 "Stack" 的参数列表
}

  对于类模版的实例化,就必须显示实例化,这个点各位读者朋友一定要记住,以上就是类模版的讲解,讲解的还是蛮少的,因为函数模版其实就把模版的一些特性讲述的很多了,类模版的讲述仅仅就是帮助读者朋友去了解类模版的使用罢了。

4.总结

  以上就是本篇博客小编所要讲述的内容,模版是C++比较重要的内容,也是一个为后面知识学习打下的基础,小编之后就要开始讲解STL库了,到时候将会给读者朋友们展示一下C++内容最爽的部分,如果本篇文章出现错误,请在评论区指出,小编定会及时回复,那么,大佬们,我们下一篇文章见啦!(牙疼真要命)