初识C++ · 模板初阶

目录

1 泛型编程

2 函数模板

3 类模板


1 泛型编程

模板是泛型编程的基础,泛型我们碰到过多次了,比如malloc函数返回的就是泛型指针,需要我们强转。

既然是泛型编程,也就是说我们可以通过一个样例来解决类似的问题,比如:

void swap(int& a,int& b)
{int tmp = a;a = b;b = tmp;
}

就交换问题来说,我们可以交换整型,可以交换浮点型,但是我们可不可以在一个文件里面实现同时交换两种类型呢?实际上对于C语言来说是不可以的,因为C语言没有模板的概念。

可能会说用typedef ,但是用了也只能解决交换其他类型的原因,不能实现同时交换两种不同的类型,也可能说用auto,但是auto不能作为函数参数使用。

这里就需要用到模板了,模板使用到了两个关键字,一个是template ,一个是typename,template是模板的英文名,typename是类型名的英文,还是很好理解的。

使用如下:

template <typename T1, typename T2,…… typename Tn>

2 函数模板

相关的关键字只有两个,这里来谈一下使用的问题,具体使用如下:

template <typename T>
//模板
void Swap(T& a,T& b)
{T tmp = a;a = b;b = tmp;
}
int main()
{int a = 1, b = 2;Swap(a, b);double c = 1.1, d = 2.2;Swap(c, d);return 0;
}

可能看起来比较抽象?

模板实现的原理是模板实例化,背后靠的都是编译器,编译器会自动推演需要的类型,所以这里会有一个问题:两次交换调用的是同一个函数吗?

当然不是的,这里可以借助汇编看一下:

汇编层面可以看到调用的函数的地址不一样,所以调用的函数不是一个函数。

模板其实是编译器在负重前面,我们使用模板的时候,编译器自动推演出我们需要的函数,

那么这里就涉及效率问题了,某种意义上来说模板的调用效率确实没有直接调用来的快,但是省事儿,我们不用再去多写那么多行代码了,毕竟函数重载也要多写代码的

基本的使用我们了解了,以后我们使用交换函数也不用自己去实现了,因为库里面有,可以直接进行使用:

现在有一些问题:

使用模板的时候,我们想要交换类型不同的怎么办?

如果我们尝试直接交换a c的话,就会报错,即没有函数模板是可以使用的

为了方便演示使用加法函数:

T Add(T x,T y)
{return x + y;
}

解决方法1->强制转换:

int main()
{int a = 1;double b = 2.5;Add(a,(int)b);return 0;
}

但是这种处理方法丢失了原本我们期待的结果,它造成了精度的丢失。

解决方法2->显式实例化:

int main()
{int a = 1;double b = 2.5;double ret = Add<double>(a,b);cout << ret;return 0;
}
int main()
{int a = 1;double b = 2.5;cout << Add<int,double>(a, b) << endl;return 0;
}

 显式实例化可以让编译器不去自动推演参数类型。

我们知道最后的结果是double类型的,所以显式调用double类型的加法函数,调用的写法是函数后面加个<>,里面写要显式调用的类型,但是呢,都差点意思。

解决方法3->多个模板混用 + auto:

template <typename T1,typename T2>
auto Add(const T1& x,const T2& y)
{return x + y;
}
int main()
{int a = 1;double b = 2.5;cout << Add(a, b) << endl;return 0;
}

既然是多参数,那么我们使用不同的模板就行,但是返回值的话,就用auto即可,这里可以说auto很妙,不会存在丢失精度的问题,也不用显式实例化,也不用强转什么的。

但是有些情况,是必须要显式实例化的:

T* Func(int a)
{T* p = (T*)operator new(sizeof(T));new(p)T(a);return p;
}

返回的是一个指针,但是函数返回什么类型呢?如果没有显式实例化的话是没有办法返回的。

这里就必须要显式实例化了:

int main()
{int a = 1;Func<int>(a);return 0;
}

再补充一个小点,typename可以用class进行代替,二者完全等价的。

template <typename T>
template <class T>

两种写法均可。

这里在引入一个点,叫匹配原则,有合适的优先选择合适的:

//整型的加法函数
int Add(int x,int y)
{cout << "int Add(int x,int y)" << endl;return x + y;
}
//通用加法函数
template <typename T1,typename T2>
auto Add(const T1& a,const T2& b)
{cout << "auto Add(const T1& a,const T2& b)" << endl;return a + b;
}
//一般加法
template<typename T>
T Add(const T& left, const T& right)
{cout << "T Add(const T& left, const T& right)" << endl;return left + right;
}

这里提供了三个函数可以实现加法,一个是类型完全匹配的,一个是通用的加法函数,一个是需要编译器需要自己推演的:

int main()
{cout << Add(1, 3) << endl;cout << Add(1, 3.3) << endl;cout << Add(1.1, 3.1) << endl;return 0;
}

那么这里的调用,就会:

第一个,因为完全匹配非模板的函数,所以优先调用;

第二个,因为更匹配通用的加法函数,需要编译器自己推演的力度没有那么大,所以调用两个模板的参数。

第三个,完全需要编译器自己推理,那就只能它了。

所以函数模板的调用也要看谁更匹配,优先使用更匹配的,编译器也想休息~


3 类模板

类模板其实后面用的最多的,现在先做个了解,比如stack,我们要实现两种栈,一个是用来存储int数据,一个是用来存储数据double的,就需要用到模板,不然解决不了一个文件存在两个类型栈的情况:

template<typename T>
class Stack
{
public:Stack(size_t capacity = 4){_array = (T*)malloc(sizeof(T) * capacity);if (nullptr == _array){perror("malloc申请空间失败");return;}_capacity = capacity;_size = 0;}void Push(const T& data);
private:T* _array;size_t _capacity;size_t _size;
};

有了模板之后,我们实现相同的就很容易了,这里如果里面的函数定义和声明分离的话,如果不是同一个.h文件的话,造成的效果是很难想象的,会造成编译的时间大幅度的增加。

分离之后的写法:

template<typename T>
class Stack
{
public:Stack(size_t capacity = 4){_array = (T*)malloc(sizeof(T) * capacity);if (nullptr == _array){perror("malloc申请空间失败");return;}_capacity = capacity;_size = 0;}void Push(const T& data);
private:T* _array;size_t _capacity;size_t _size;
};
template<class T>
void Stack<T>::Push(const T& data)
{;
}

创建不同的Stack就显式实例化就可以了:

int main()
{stack<int> p1;stack<double> p2;return 0;
}

模板初阶还是好理解的,后面介绍高阶的。


感谢阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/678868.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI图书推荐:AI在语言学习教育领域的应用和挑战

这本书《AI在语言学习教育领域的应用和挑战》&#xff08;AI in Language Teaching, Learning, and Assessment&#xff09;由Fang Pan编辑&#xff0c;出版于IGI Global&#xff0c;主要探讨了人工智能&#xff08;AI&#xff09;在语言教育领域的应用、挑战以及潜在的益处。 …

C++:菱形继承与菱形虚拟继承

一、菱形继承 单继承&#xff1a;一个子类只有一个直接父类时称这个继承关系为单继承 多继承&#xff1a;一个子类有两个或以上直接父类时称这个继承关系为多继承 菱形继承&#xff1a;菱形继承是多继承的一种特殊情况&#xff0c;派生类继承自两个间接基类&#xff0c;而这…

java--io流(一)

1. 前置知识 字符集是什么&#xff1f; 字符集&#xff08;Character Set&#xff09;是一组字符的集合&#xff0c;它定义了可以在计算机系统中使用的所有字符。字符集可以包括字母、数字、标点符号、控制字符、图形符号等。字符集使得计算机能够存储、处理和显示各种语言和…

理解DPI:从数码到打印的深入分析

目录标题 1. DPI的定义2. DPI与图像质量2.1. 对于打印来说&#xff1a;2.2. 对于屏幕显示来说&#xff1a; 3. 如何计算DPI4. 调整DPI4.1. 提高DPI&#xff1a;4.2. 降低DPI&#xff1a; 5. DPI与图像文件大小的关系6. 实际应用中的DPI6.1. 专业打印&#xff1a;6.2. 屏幕设计&…

如何在Ubuntu系统上定制文件系统

基于全志T507H处理器设计研发的OKT507-C开发板为例进行介绍。 Forlinx Desktop(Ubuntu)系统基于Ubuntu官方为嵌入式设备制作的操作系统-Lubuntu&#xff0c;该操作系统具备apt-get、ldd等常用的命令&#xff0c;若需要安装软件则直接apt-get在线安装即可&#xff0c;不需进行交…

DDPM与扩散模型

很早之前就新建了一个专栏从0开始弃坑扩散模型 ,但发了一篇文章就没有继续这一系列&#xff0c;在这个AIGC的时代&#xff0c;于是我准备重启这个专栏。 整个专栏的学习顺序可以见这篇汇总文章 这是本专栏的第一章 目录 引言生成模型的发展历程 引言 扩散模型( Diffusion Mode…

数据结构-线性表-链表-2.3-6

有一个带头结点的单链表L&#xff0c;设计一个算法使其元素递增有序。 void sort(Linklist &L){LNode *pL->next,*pre;LNode *rp->next;p->nextNULL;pr;while(p){rp->next;preL;while(pre->next!NULL&&pre->next->data<p->data){prepre…

ACM实训冲刺第一天

目录 ACM实训课程考核 考核内容 备赛安排 推荐学习资源 ACM实训准备规划 前话 历届习题&#xff08;未曾改变&#xff09; 第0套 第1套 第2套 第3套 第4套 规划 5.8 - 5.12 &#xff08;11周&#xff09; 5.13-5.19&#xff08;12周&#xff09; 5.20-5.26&…

【计算机毕业设计】基于SSM++jsp的菜匣子优选系统【源码+lw+部署文档+讲解】

目录 第一章 绪 论 第二章 关键技术的研究 2.1 JSP技术介绍 2.2 JAVA简介 2.3 ECLIPSE 开发环境 2.4 Tomcat服务器 2.5 MySQL数据库 第三章 系统分析 3.1 系统设计目标 3.2 系统可行性分析 3.3 系统功能分析和描述 3.4系统UML用例分析 3.4.1管理员用例 3.4.2用户用例 3.5系统流…

远动通讯屏的作用

远动通讯屏的作用 远动通讯屏有时有称为调度数据网柜&#xff0c;远动通讯屏具体干啥作用&#xff1f;远动通讯屏是以计算机为基础的生产过程与调度自动化系统&#xff0c;可以对现场的运行设备进行监视和控制、以实现数据采集、设备测量、参数调节以及各类信号报警等各项功能。…

【Android】源码解析Activity的结构分析

源码解析Activity的结构分析 目录 1、Activity、View、Window有什么关联&#xff1f;2、Activity的结构构建流程3 源码解析Activity的构成 3.1 Activity的Attach方法3.2 Activity的OnCreate 4、WindowManager与View的关系总结 1、一个Activity对应几个WindowManage&#xff0…

软考143-下午题-【试题二】:E-R图、关系模式

一、分值与目标 15分&#xff0c;目标10 二、题目形式 示例&#xff1a; 三、E-R图的基本图形元素 示例&#xff1a; 3-1、实体 1、弱实体 在现实世界中有一种特殊的联系&#xff0c;这种联系代表实体间的所有 (Ownership) 关系&#xff0c;例如&#xff1a;职工与家属的联系…