文档章节

C++中的模板那点事

o
 onedotdot
发布于 2017/09/12 13:37
字数 2607
阅读 8
收藏 0
点赞 0
评论 0

1.什么是模板

假设现在我们完成这样的函数,给定两个数x和y求式子x^2 + y^2 + x * y的值 .考虑到x和y可能是 int , float 或者double类型,那么我们就要完成三个函数:

int fun(int x,int y);

float fun(float x,float y);

double fun(double x,double y);

并且每个fun函数内部所要完成的操作也是极其的相似。如下:

复制代码

1 int fun(int x,int y)
 2 {
 3     int tmp = x *x + y * y + x * y;
 4     return tmp;
 5 }
 6 float fun(float x,float y)
 7 {
 8     float tmp = x *x + y * y + x * y;
 9     return tmp;
10 }
11 double fun(double x,double y)
12 {
13     double tmp = x *x + y * y + x * y;
14     return tmp;
15 }

复制代码

可以看出,上面的三个函数体除了类型不一样之外,其他的完全一样,那么如果能够只写一个函数就能完成上面的三个函数的功能该多好呢?如果从这三个函数提炼出一个通用函数,而它又适用于这三种不同类型的数据,这样会使代码的重用率大大提高。实际上C++中的模板正好就是来解决这个问题的。模板可以实现类型的参数化(把类型定义为参数),从而实现了真正的代码可重用性。C++中的模板可分为函数模板和类模板,而把函数模板的具体化称为模板函数,把类模板的具体化成为模板类。下面让我们分别看看什么是函数模板和类模板吧~~~

2.模板函数

实际上我们利用函数模板,只需要一个函数就可能完成上面的三个函数了,千言万语不如看代码: 

复制代码

1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 template <typename T>
 6 T fun(T x,T y)
 7 {
 8     T tmp = x *x + y * y + x * y;
 9     return tmp;
10 }
11 int main()
12 {
13     int x1 = 1,y1 = 4;
14     float x2 = 1.1 , y2 = 2.2;
15     double x3 = 2.0 , y3 = 3.1;
16     cout<<fun(x1,y1)<<endl;
17     cout<<fun(x2,y2)<<endl;
18     cout<<fun(x3,y3)<<endl;
19     return 0;
20 }

复制代码

运行结果:

如此利用模板,我们很轻而易举的达到了我们的目的,而这也大大的提高了代码的可重用性,这也让我们想起了STL中的那些算法了吧,这些算法使用多种的数据类型。实际上STL即使模板的重要应用了。

现在我们想,如果上面的代码这样调用fun(x1,y2)会怎么样呢?点击编译会出现这样的错误:

可以看到编译编译出现问题的是fun(x1,y2),说的意思就是没有对应的函数,要么x1和y2都是int型,要么x1和y2都是float型。那么我为什么要说一下这样一种情况呢?主要是为了引出模板也可以同时使用两个:

复制代码

1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 
 6 template <typename T1 , typename T2>
 7 T2 fun(T1 x,T2 y)
 8 {
 9     T2 tmp = x *x + y * y + x * y;
10     return tmp;
11 }
12 int main()
13 {
14     int x1 = 1,y1 = 4;
15     float x2 = 1.1 , y2 = 2.2;
16     double x3 = 2.0 , y3 = 3.1;
17     cout<<fun(x1,y1)<<endl;
18     cout<<fun(x2,y2)<<endl;
19     cout<<fun(x3,y3)<<endl;
20     cout<<fun(x1,y2)<<endl;
21     return 0;
22 }

复制代码

运行结果:

当使用两个模板时,为什么fun(x1,y1)也能正确运行呢?因为当进行这个调用时,T1 = int ,T2 = int。所以这种调用也是没有问题的。

提到函数想到重载是很自然的吧,那么模板函数能不能重载呢?显然是能的了,还是看代码:

复制代码

1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 
 6 template <typename T1 , typename T2>
 7 T2 fun(T1 x,T2 y)
 8 {
 9     cout<<"调用了两个个参数的 fun 函数 ^^ "<<endl;
10     T2 tmp = x *x + y * y + x * y;
11     return tmp;
12 }
13 template <typename T>
14 T fun(T x , T y , T z)
15 {
16     cout<<"调用了三个参数的 fun 函数 ^^ "<<endl;
17     T tmp = x * x + y * y + z * z + x * y * z; 
18     return tmp;
19 }
20 int main()
21 {
22     int x1 = 1 , y1 = 4 , z1 = 5;
23     float x2 = 1.1 , y2 = 2.2;
24     double x3 = 2.0 , y3 = 3.1;
25     cout<<fun(x1,y1)<<endl;
26     cout<<fun(x2,y2)<<endl;
27     cout<<fun(x3,y3)<<endl;
28     cout<<fun(x1,y2)<<endl;
29     cout<<fun(x1,y1,z1)<<endl;
30     return 0;
31 }

复制代码

运行结果:

从结果已经能看出来模版函数的重载是没有任何问题的了。那么模板函数和非模板函数之间是否能够重载呢??

复制代码

1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 template <typename T>
 6 T fun(T x,T y)
 7 {
 8     cout<<"调用了模板函数 ^^ "<<endl;
 9     T tmp = x * x + y * y + x * y;
10     return tmp;
11 }
12 int fun(int x,int y)
13 {
14     cout<<"调用了非模板函数 ^^ "<<endl;
15     int tmp = x * x + y * y + x * y;
16     return tmp;
17 }
18 
19 int main()
20 {
21     int x1 = 1 , y1 = 4;
22     float x2 = 1.1 , y2 = 2.2;
23     cout<<fun(x1,y1)<<endl;
24     cout<<fun(x2,y2)<<endl;
25     return 0;
26 }

复制代码

运行结果:

看以看出模版函数和非模板函数也是可能重载的,那么重载函数的调用顺序是怎么样的呢?实际上是先查找非模板函数,要有严格匹配的非模板函数,就调用非模板函数,找不到适合的非模板函数在和模板函数进行匹配。

到这里,关于模板就说这些吧~~~~

3.模板类

要是理解了模版函数,模板类就相当的简单了,只不过模版函数是对函数中的类型使用模板,而模板类是对类中的类型使用模板,这我就不多说了,下面的代码是我以前利用模板写的单链表,这个是模板的典型应用:(测试过)

复制代码

1 #include <stdio.h>
  2 #include <iostream.h>
  3 
  4 template <class T>
  5 struct SLNode
  6 {
  7     T data;
  8     SLNode<T> *next;
  9     SLNode(SLNode<T> *nextNode=NULL)
 10     {
 11         next = nextNode;
 12     }
 13     SLNode(const T &item,SLNode<T> *nextNode=NULL)
 14     {
 15         data = item;
 16         next = nextNode;
 17     }
 18 };
 19 
 20 template <class T>
 21 class SLList
 22 {
 23 private:
 24     SLNode<T> *head;
 25     SLNode<T> *tail;
 26     SLNode<T> *currptr;
 27     int size;
 28 public:
 29     SLList();
 30     SLList(const T &item);
 31     ~SLList();
 32     bool IsEmpty()const;
 33     int Length()const;
 34     bool Find(int k,T &item)const;
 35     int Search(const T &item)const;
 36     void InsertFromHead(const T &item);
 37     void InsertFromTail(const T &item);
 38     bool DeleteFromHead(T &item);
 39     bool DeleteFromTail(T &item);
 40     void Insert(int k,const T &item);
 41     void Delete(int k,T &item);
 42     void ShowListMember();
 43 };
 44 //构造函数
 45 template <class T>
 46 SLList<T>::SLList()
 47 {
 48     head = tail = currptr = new SLNode<T>();
 49     size = 0;
 50 }
 51 //构造函数
 52 template <class T>
 53 SLList<T>::SLList(const T &item)
 54 {
 55     tail = currptr = new SLNode<T>(item);
 56     head = new SLNode<T>(currptr);
 57     size = 1;
 58 }
 59 //析构函数
 60 template <class T>
 61 SLList<T>::~SLList()
 62 {
 63      SLNode<T> *temp;
 64     while(!IsEmpty())
 65     {
 66         temp = head->next;
 67         head->next = temp->next;
 68         delete temp;
 69         
 70     }
 71 }
 72 //判断链表是否为空
 73 template <class T>
 74 bool SLList<T>::IsEmpty()const
 75 {
 76     return head->next == NULL;
 77 }
 78 //返回链表的长度
 79 template <class T>
 80 int SLList<T>::Length()const
 81 {
 82      return size;
 83 }
 84 //查找第k个节点的阈值
 85 template <class T>
 86 bool SLList<T>::Find(int k,T &item)const
 87 {
 88     if(k < 1)
 89     {
 90         cout<<"illegal position !"<<endl;
 91     }
 92     SLNode<T> *temp = head;
 93     int count = 0;
 94     while(temp != NULL && count < k)
 95     {
 96         temp = temp->next;
 97         count++;
 98     }
 99     if(temp == NULL)
100     {
101         cout<<"The list does not contain the K node !"<<endl;
102         return false;
103     }
104     item = temp->data;
105     return true;
106 }
107 //查找data阈值为item是表的第几个元素
108 template <class T>
109 int SLList<T>::Search(const T &item)const
110 {
111     SLNode<T> *temp = head->next;
112     int count = 1;
113     while(temp != NULL && temp->data != item)
114     {
115         temp = temp->next;
116         count++;
117     }
118     if(temp == NULL)
119     {
120         cout<<"The node does not exist !"<<endl;
121         return -1;
122     }
123     else
124     {
125         return count;
126     }
127 }
128 //从表头插入
129 template <class T>
130 void SLList<T>::InsertFromHead(const T &item)
131 {    
132     if(IsEmpty())
133     {
134         head->next = new SLNode<T>(item,head->next);
135         tail = head->next;
136     }
137     else
138     {
139         head->next = new SLNode<T>(item,head->next);
140     }
141     size++;
142 }
143 //从表尾插入
144 template <class T>
145 void SLList<T>::InsertFromTail(const T &item)
146 {
147     tail->next = new SLNode<T>(item,NULL);
148     tail = tail->next;
149     size++;
150 }
151 //从表头删除
152 template <class T>
153 bool SLList<T>::DeleteFromHead(T &item)
154 {
155     if(IsEmpty())
156     {
157         cout<<"This is a empty list !"<<endl;
158         return false;
159     }
160     SLNode<T> *temp = head->next;
161     head->next = temp->next;
162     size--;
163     item = temp->data;
164     if(temp == tail)
165     {
166         tail = head;
167     }
168     delete temp;
169     return true;
170 }
171 //从表尾删除
172 template <class T>
173 bool SLList<T>::DeleteFromTail(T &item)
174 {
175     if(IsEmpty())
176     {
177         cout<<"This is a empty list !"<<endl;
178         return false;
179     }
180     SLNode<T> *temp = head;
181     while(temp->next != tail)
182     {
183         temp = temp->next;
184     }
185     item = tail->data;
186     tail = temp;
187     tail->next=NULL;
188     temp = temp->next;
189     delete temp;
190     size--;
191     return true;
192 }
193 //在第k个节点后插入item值
194 template <class T>
195 void SLList<T>::Insert(int k,const T &item)
196 {
197     if(k < 0 || k > size)
198     {
199         cout<<"Insert position Illegal !"<<endl;
200         return;
201     }
202     if(k == 0)
203     {
204         InsertFromHead(item);
205         return;
206     }
207     if(k == size)
208     {
209         InsertFromTail(item);
210         return;
211     }
212     SLNode<T> *temp = head->next;
213     int count = 1;
214     while(count < k)
215     {
216         count++;
217         temp = temp->next;
218     }
219     SLNode<T> *p = temp->next;
220     temp->next = new SLNode<T>(item,p);
221     size++;
222 }
223 //删除第k个节点的值,保存在item中
224 template <class T>
225 void SLList<T>::Delete(int k,T &item)
226 {
227     if(k <= 0 || k > size)
228     {
229         cout<<"Ileegal delete position !"<<endl;
230         return;
231     }
232     if(k == 1)
233     {
234         DeleteFromHead(item);
235         return;
236     }
237     if(k == size)
238     {
239         DeleteFromTail(item);
240         return;
241     }
242     SLNode<T> *temp = head->next;
243     int count = 1;
244     while(count < k-1)
245     {
246         count++;
247         temp = temp->next;
248     }
249     SLNode<T> *p = temp->next;
250     temp->next = p->next;
251     p->next = NULL;
252     item = p->data;
253     delete p;
254     size--;
255 }
256 template <class T>
257 void SLList<T>::ShowListMember()
258 {
259     cout<<"List Member : ";
260     SLNode<T> *temp = head->next;
261     while(temp != NULL)
262     {
263         cout<<temp->data<<" ";
264         temp = temp->next;
265     }
266     cout<<endl;
267 }
268 
269 /*
270 1.引入了InsertFronHead,InsertFromTail,DeleteFromHead和DeleteFromTail用来实现
271   Insert和Delete函数,是一个比较好的方法。
272 2.SLNode(T &item,SLNode<T> *nextNode)这个构造函数设计的非常巧妙,便于其他成员
273   函数的实现。
274 3.插入,删除分为:表头,表尾,中间插入(删除)三种情况
275 */
276 
277 
278 
279 int main()
280 {
281     int item;
282     SLList<int> list(12);
283 
284     list.Insert(0,11);
285     cout<<"list number:"<<list.Length()<<endl;
286     list.ShowListMember();
287 
288     list.Insert(2,14);
289     cout<<"list number:"<<list.Length()<<endl;
290     list.ShowListMember();
291 
292     list.Insert(2,13);
293     cout<<"list number:"<<list.Length()<<endl;
294     list.ShowListMember();
295 
296     list.Delete(2,item);
297     cout<<"item = "<<item<<endl;
298     cout<<"list number:"<<list.Length()<<endl;
299     list.ShowListMember();
300 
301     list.Delete(1,item);
302     cout<<"item = "<<item<<endl;
303     cout<<"list number:"<<list.Length()<<endl;
304     list.ShowListMember();
305 
306     list.Delete(2,item);
307     cout<<"item = "<<item<<endl;
308     cout<<"list number:"<<list.Length()<<endl;
309     list.ShowListMember();
310     return 0;
311 }

复制代码

利用模板的好处是,SLList中的数据可以是任意的数据类型,这也就是泛型编程的概念了吧~~~~

本文转载自:http://www.cnblogs.com/BeyondAnyTime/archive/2012/08/13/2636963.html

共有 人打赏支持
o
粉丝 6
博文 320
码字总数 14350
作品 0
朝阳
C语言/C++编程学习强势之处的体现

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界
05/12
0
0
C++11 中值得关注的几大变化

源文章来自前C++标准委员会的 Danny Kalev 的 The Biggest Changes in C++11 (and Why You Should Care),赖勇浩做了一个中文翻译在这里。所以,我就不翻译了,我在这里仅对文中提到的这些变...

雅各宾
2014/01/17
0
0
C++ STL编程轻松入门 1

作为C++标准不可缺少的一部分,STL应该是渗透在C++程序的角角落落里的。STL不是实验室里的宠儿,也不是程序员桌上的摆设,她的激动人心并非昙花一现。本教程旨在传播和普及STL的基础知识,若...

暖冰
2015/11/21
0
0
[开源世界]从自动导出动态链接库接口看C++的缺点

自动导出动态链接库接口在C++编程中绝对是一件烦人的事情,因为你不得不大量的重复以下几个步骤: 1.加载动态链接库 2.定义导出函数指针定义 3.定义导出函数指针变量 4.从动态链接库中导出函...

梁欢
2013/10/21
0
2
STL vector 介绍连载1-2-3

STL简介: STL = Standard Template Library,标准模板库,惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室工作时所开发出来的。这可能是...

天远
2012/05/20
0
0
在学校和老师学习C/C++你学到了什么?

计算机行业在未来是一个具有无限潜力的行业,但同样行业竞争力也是十分强烈,同样事靠计算机吃饭的,你是职业叫码农,人家的职业叫程序员,大牛的职业是架构师、分析师,你甘心成为一个日夜加...

悟空_b201
04/10
0
0
篮子、水果和鸡蛋——关于C++的模板偏特化和萃取编程技法

最近在读《STL源码剖析》。读这本书的时候发现自己的C++的知识其实是非常匮乏的。 从大学的C++教材上学到一些C++基本的语法、内存管理、继承、多态等方面的基础知识。这些只是是一棵大树的根...

costaxu
2012/12/22
0
0
C++十种方法"Hello World"

初学编程,无论是VB,C/C++,Java,C#大多都是从Hellow World这个程序开 始的,也是最常见的入门方法。C/C++本身有很多特性和用发,这里就用十种方法 实现Hellow World这个程序. 1. 最经典的...

程序鸡
2012/12/07
0
3
Linux C++、Boost、ACE ......

Linux/UNIX、C++、Boost、ACE、Shell ...... Linux/UNIX C++高级培训---远程班 培养目标:Linux/UNIX C++高级软件工程师 专注Linux/UNIX服务器端的软件开发(后台开发),培养企业所需的专业...

athxy
2010/04/01
0
1
C++中的 .h 和 .cpp 区别详解

在C++编程过程中,随着项目的越来越大,代码也会越来越多,并且难以管理和分析。于是,在C++中就要分出了头(.h)文件和实现(.cpp)文件,并且也有了Package的概念。 对于以C起步,C#作为“母语...

刘小米
2014/09/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

前端基础

1. get请求传参长度的误区 误区:我们经常说get请求参数的大小存在限制,而post请求的参数大小是无限制的。 实际上HTTP 协议从未规定 GET/POST 的请求长度限制是多少。对get请求参数的限制是...

wenxingjun
今天
0
0
Android 复制和粘贴功能

做了一回搬运工,原文地址:https://blog.csdn.net/kennethyo/article/details/76602765 Android 复制和粘贴功能,需要调用系统服务ClipboardManager来实现。 ClipboardManager mClipboardM...

她叫我小渝
今天
0
0
拦截SQLSERVER的SSL加密通道替换传输过程中的用户名密码实现运维审计(一)

工作准备 •一台SQLSERVER 2005/SQLSERVER 2008服务 •SQLSERVER jdbc驱动程序 •Java开发环境eclipse + jdk1.8 •java反编译工具JD-Core 反编译JDBC分析SQLSERVER客户端与服务器通信原理 SQ...

紅顏為君笑
今天
6
0
jQuery零基础入门——(六)修改DOM结构

《jQuery零基础入门》系列博文是在廖雪峰老师的博文基础上,可能补充了个人的理解和日常遇到的点,用我的理解表述出来,主干出处来自廖雪峰老师的技术分享。 在《零基础入门JavaScript》的时...

JandenMa
今天
0
0
linux mint 1.9 qq 安装

转: https://www.jianshu.com/p/cdc3d03c144d 1. 下载 qq 轻聊版,可在百度搜索后下载 QQ7.9Light.exe 2. 去wine的官网(https://wiki.winehq.org/Ubuntu) 安装 wine . 提醒网页可以切换成中...

Canaan_
今天
0
0
PHP后台运行命令并管理运行程序

php后台运行命令并管理后台运行程序 class ProcessModel{ private $pid; private $command; private $resultToFile = ''; public function __construct($cl=false){......

colin_86
今天
1
0
数据结构与算法4

在此程序中,HighArray类中的find()方法用数据项的值作为参数传递,它的返回值决定是否找到此数据项。 insert()方法向数组下一个空位置放置一个新的数据项。一个名为nElems的字段跟踪记录着...

沉迷于编程的小菜菜
今天
1
1
fiddler安装和基本使用以及代理设置

项目需求 由于开发过程中客户端和服务器数据交互非常频繁,有时候服务端需要知道客户端调用接口传了哪些参数过来,这个时候就需要一个工具可以监听这些接口请求参数,已经接口的响应的数据,这种...

银装素裹
今天
0
0
Python分析《我不是药神》豆瓣评论

读取 Mongo 中的短评数据,进行中文分词 对分词结果取 Top50 生成词云 生成词云效果 看来网上关于 我不是药神 vs 达拉斯 的争论很热啊。关于词频统计就这些,代码中也会完成一些其它的分析任...

猫咪编程
今天
0
0
虚拟机怎么安装vmware tools

https://blog.csdn.net/tjcwt2011/article/details/72638977

AndyZhouX
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部