【C++】模板:了解泛型编程

网友投稿 1377 2022-11-21 16:55:04

【C++】模板:了解泛型编程

本篇是C++模板学习的一些笔记

文章目录

​​1.了解泛型编程​​​​2.函数模板​​

​​3.类模板​​

​​4.等待添加……​​

1.了解泛型编程

泛型编程,故如其名,是一个泛化的编程方式。其实现原理为程序员编写一个函数/类的代码示例,让编译器去填补出不同的函数实现

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

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

2.函数模板

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

2.1简单示例

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

templatevoid Swap(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 ​​

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

void Show(int left, double right){ cout << typeid(left).name() << endl; cout << typeid(right).name() << endl;}

2.3模板实例化

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

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

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

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

templateT* test(int num){ return new T[num];}

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

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

templateT* test(int num){ return new T[num];}

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

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

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

templatevoid Add(T1 left, T1 right=10){ cout << "Add temp "<

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

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

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

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

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

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

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

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

这是为什么呢?

有无解决办法?

其实是有的,我们可以在模板函数定义的​​.cpp​​中对我们需要使用的函数进行显式实例化指定

显式实例化需要对我们要用的所有函数进行实例化,比如你需要用double类型,只显示实例化了int类型是不行的,依旧会报错。

3.类模板

类模板的基本形式如下,这里作为一个小区分,我用​​class​​​来当作模板参数名。实际上​​typename​​也是可以的

templateclass 类模板名{// 类内成员定义};

3.1简单示例

下面用一个非常简单的顺序表代码来演示一下类模板

templateclass List{public: List(int capacity = 10) : _a(new T[capacity]) , _size(0) , _capa(capacity) {} ~List(); T& operator[](int pos) { assert(pos < _size); return _a[pos]; }private: T* _a; int _size; int _capa;};//类模板中函数放在类外进行定义时,需要加模板参数列表template List::~List(){ delete[] _a; _size = _capa = 0;}

可以看到,通过显式实例化的方式,我们成功让这个类模板变成了两个不同类型的顺序表

//类模板中函数放在类外进行定义时,需要加模板参数列表template List::~List(){ delete[] _a; _size = _capa = 0;}

templateclass List ;templateclass List ;

需要什么类型的类,就得实例化这个类型。

4.等待添加……

模板还有更多值得学习的内容,待我先捣鼓一下,再回来更新这篇博客

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:技术与业务同等重要,偏向任何一方都是错误
下一篇:教你快速学会JPA中所有findBy语法规则
相关文章