C++超详细讲解泛型
2026/4/27 10:01:29 网站建设 项目流程

就好比活字印刷术,可以灵活调整印刷的板块和内容,比只能固定印刷某一个内容的雕版印刷术效率更高,也让印刷术由此得到了更广泛的应用。

在C++中,函数重载和模板的出现,让泛型编程得到了实际的应用。其中模板,就是类似活字印刷术一样的存在。

2.函数模板

八八了那么多没用的,让我们来看看函数模板的语法实现吧

2.1简单示例

下面是一个最简单的交换函数的例子,通过标明模板参数T,让编译器自动识别函数传参,并调用出不同的函数

1

2

3

4

5

6

7

template<typenameT>

voidSwap(T& left,T& right)

{

T temp = left;

left = right;

right = temp;

}

其中,typename是定义模板的关键字,我们可以使用class来替代,但不能使用struct

可以看到,编译器成功调用了Swap函数,交换了int类型和double类型

2.2多个模板参数

如果我们尝试把int和double同时传参给这个函数,会发生什么呢?

编译器会报错,表示模板参数T不明确

这时候我们有几种解决方法

首先是将double强转为int(反过来亦可)

你会发现还是不行,那是因为强转并不支持用double引用int。所以我们把函数传参中的引用去掉,即可正常调用这个函数(暂且不提传引用和传值的区别)

使用多个模板参数

和函数传参类似,我们也可以设置多个模板参数

在下图中,我使用typeid关键字来打印模板参数T1和T2的类型。

使用typeid需要包含头文件#include <typeinfo>

可以看到,实际上函数在调用这个模板的时候,已经实例化了这个函数(即替换模板参数为正确参数类型)这时候在后台处理的时候,其实Show函数已经实例化为了下面这个样子

1

2

3

4

5

voidShow(intleft,doubleright)

{

cout <<typeid(left).name() << endl;

cout <<typeid(right).name() << endl;

}

2.3模板实例化

上面的方式,是编译器自动帮我们实例化模板参数。在实际使用中,我们还可以自己指定实例化为什么类型

  • 利用强制类型转换
  • 使用<int>直接指定实例化为int类型

使用第二种方式的时候,编译器会对另外一个不匹配的参数进行隐式类型转换。如果转换不成功,则会报错。

另外注意的是,函数模板参数T同样可以用来作为返回值,但是不能通过返回值来推断参数T的类型。比如下面这个函数,我们在使用的时候就需要直接指定模板参数T,而不能写一个int* ptr=test(10)让编译器通过“返回值是int*接收的,所以函数模板参数T是int”来推断。

1

2

3

4

5

template<typenameT>

T* test(intnum)

{

returnnewT[num];

}

函数模板支持给予参数缺省值

当一个参数不确定的时候,函数模板是支持给予缺省值的

1

2

3

4

5

template<typenameT=char>

T* test(intnum)

{

returnnewT[num];

}

比如这样,当我们没有直接指定的时候,编译器就会将T作为char类型,返回一个num大小的char(一个字节)的空间

注意:当有多个模板参数时,缺省值需要从右往左给

函数模板的传参也支持缺省值

1

2

3

4

5

6

7

8

9

10

11

template<typenameT1>

voidAdd(T1 left, T1 right=10)

{

cout <<"Add temp "<<typeid(left).name() <<" "<<typeid(right).name() << endl;

cout << left + right << endl << endl;

}

intmain()

{

inta=1;

Add(a);

}

在这种情况下,编译器会正确调用该函数模板

2.4模板和普通函数同时存在

以Add函数为例,在函数模板存在的同时,我们还可以单独写一个int类型的add函数。这都归功于函数重载的存在。

同时,我们还可以使用<int>来指定函数模板重载为已存在的Add函数。因为本质上这两个函数是不同的,并不会冲突。

函数在调用的时候,首先会去调用已经存在的函数。当参数和已存在的函数不匹配时,才会调用函数模板

2.5函数模板不支持定义和声明分离

一般情况下,我们都会在头文件中生命函数,在另外一个源文件中定义函数。

但是模板是不支持这么做的!编译器会报错 链接错误

error LNK2019:无法解析的外部符号……

所以我们需要将函数模板的声明和定义放在一个头文件中。在部分使用场景,会使用.hpp来表示这个头文件是包含了函数定义的(即.h和.cpp的集合体)。需要注意,这并不是一个硬性要求,你也可以直接使用.h,并将声明和定义放入其中。

这是为什么呢?

因为单独的.h声明会在源文件顶部展开,而此时函数模板正常推演参数,但编译器并没有找到函数的实现,即这是一个没有地址的函数。从而导致编译器找不到函数的地址,产生了符号表的链接错误有无解决办法?

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询