模版初阶(更新)
模版介绍
函数模版分为两个类型:
- 函数模版
- 类模版
函数模版
语法格式: 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; //int
Stack st2; //double
return 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; //int
Stack<double> st2; //double
return 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>才是我们的模版类型。
结言
本文只是简单介绍了模版的基本概念,后期学了更深的内容会持续更新…
原文地址:https://blog.csdn.net/anjibgdexuexi/article/details/140334341
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!