文章目录
- 模版介绍
- 函数模版
- 模版匹配规则
- 类模版
- 结言
模版介绍
函数模版分为两个类型:
- 函数模版
- 类模版
函数模版
语法格式: t e m p l a t e < t y p n a m e T 1 , t y p n a m e T 2... > template<typname T1,typname T2...> template<typnameT1,typnameT2...>
void swap(int& a, int& b)
{int tmp = a;a = b;b = tmp;
}
void swap(double& a, double& b)
{double tmp = a;a = b;b = tmp;
}int main()
{int a = 1, b = 2;double c = 1.1, d = 2.2;cout << a << " " << b << endl;swap(a, b);cout << a << " " << b << endl;cout << "----------------" << endl;cout << c << " " << d << endl;swap(c, d);cout << c << " " << d << endl;return 0;
}
在C语言中,如果我们需要分别交换 i n t int int 或 d o u b l e double double 的数据,那么我们需要定义两个swap函数并且还不能重名。(C语言并不支持函数重载)。
而在C嘎嘎中:
我们只需要写一个模版就可以了。这里的T在编译的时候会默认替换为我们的 i n t int int和 d o u b l e double double
同时通过调试发现,这两个swap都进入我们写的函数模版,那么这两个Swap调用的是同一个函数吗?
通过反汇编发现,此时我们两个调用的并不是同一个函数。
当我们使用我们的 S w a p ( ) Swap() Swap()模版的时候,编译器会去默认推演我们此时的参数类型,然后编译器自动生成一个 S w a p ( ) Swap() Swap()函数,中国有句古话:死道友不死贫道[doeg]。咱们只管写一个模版,其他的交给编译器。
但是如果我们只有一个模版参数的话,传入两个不同类型编译器推导不出来。
此时我们有以下几种方法:
- 添加模版参数
- 进行强制类型转化
- 直接给定模版参数类型,不让编译器推演
A d d < i n t > Add<int> Add<int> 这个叫做显式实例化。它指定了参数的类型,编译器就不会推演了,T默认会 i n t int int 类型。
模版匹配规则
如上图:当我们调用 A d d ( a , b ) Add(a,b) Add(a,b) 的时候,我们写的单参数模版函数其实可以实现的,但是编译器回去默认调用最匹配的 i n t A d d ( i n t l e f t , i n t r i g h t ) int Add(int left, int right) intAdd(intleft,intright)。
而当我们调用 A d d ( a , c ) Add(a,c) Add(a,c) 的时候不同参数类型我们的单参数模版函数就不行了,第一张图中我们定义了两个参数的模版参数,所以编译器会去调用我们定义的这个模版函数,而在第二张图中,编译器由于没得选了,只能被迫去调用
i n t A d d ( i n t l e f t , i n t r i g h t ) int Add(int left, int right) intAdd(intleft,intright),只不过会有 精度的丢失。
总结一下:
- 函数调用会优先调用 (参数匹配+口味好)例如: A d d ( a , b ) Add(a,b) Add(a,b)调用 i n t A d d ( i n t l e f t , i n t r i g h t ) int Add(int left, int right) intAdd(intleft,intright)
- 当口味不对的时候,会优先调用参数匹配 例如: A d d ( a , c ) Add(a,c) Add(a,c)调用 t e m p l a t e < t y p e n a m e T 1 , t y p e n a m e T 2 > template<typename T1, typename T2> template<typenameT1,typenameT2>
- 当两个都没有的时候,会将就一样。例如: A d d ( a , c ) Add(a,c) Add(a,c)调用 i n t A d d ( i n t L e f t , i n t R i g h t ) int Add(int Left, int Right) intAdd(intLeft,intRight)
当然模版函数只是单参数的时候,我们传入两个不同类型的参数时,就会报错,编译器不知道推演哪一个?
类模版
typedef int DataType;
class Stack
{
public:Stack(){_array = (DataType*)malloc(sizeof(DataType) * 3);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = 3;_size = 0;}void Push(DataType data){_array[_size] = data;_size++;}~Stack(){if (_array){free(_array);_array = NULL;_capacity = 0;_size = 0;}}
private:DataType* _array;int _capacity;int _size;
};
如上述栈,在C语言中,如果我们想要栈中存不同数据。
int main()
{Stack st1; //intStack st2; //doublereturn 0;
}
例如我们想要一个存 i n t int int,一个存 d o u b l e double double,那我们就需要写两个栈了,由于这两个栈的代码都类似,那么在C++中,我们可以定义模版,栈的数据类型,有模版来代替,这样想要存什么类型,直接示例化什么类型的即可。
template<typename T>
class Stack
{
public:Stack(){_array = (T*)malloc(sizeof(T) * 3);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = 3;_size = 0;}void Push(T data){_array[_size] = data;_size++;}~Stack(){if (_array){free(_array);_array = NULL;_capacity = 0;_size = 0;}}
private:T* _array;int _capacity;int _size;
};int main()
{Stack<int> st1; //intStack<double> st2; //doublereturn 0;
}
当然我们的模版也可以把声明和定义分开,但是注意: 模版的定义和声明要分离也分离在 .h 文件中,最好不要一个在 .h 文件 一个在 .cpp文件,这样会让编译的时间大大增加。
同时我们的T还要另外声明一次,不然编译器不知道T是哪来的。类域声明的时候我们要 S t a c k < i n t > Stack<int> Stack<int>这样写。因为此时我们的 S t a c k < i n t > Stack<int> Stack<int>才是我们的模版类型。
结言
本文只是简单介绍了模版的基本概念,后期学了更深的内容会持续更新…