面向对象程序设计(二):C++模板初探
背景:老师留了一个作业,对两个数组进行相加,但是总是会出现错误;首先我们需要知道当数组作为参数传递的时候是不能用 sizeof 的,因为当数组传入子函数就变成了普通的数组头;这时候使用 sizeof 只会检测到指针的长度;
我们用模板来传递数组,实际上并非模板可以传递数组,而是引用传递完成了这件事
对应的现象是:值传递的数组会衰减成指针
下面给出利用引用传递的代码(没有使用模板)
1 #include<iostream>
2 using namespace std;
3
4 int P(int (&a)[5]); //子函数
5 int main(){
6
7 int a[5]={0};
8
9 int b=P(a);
10
11 cout<<b<<endl;
12
13 return 0;
14 }
15 int P(int (&a)[5]){ //进行了引用传递
16
17 return sizeof(a)/sizeof(a[0]);
18 }
在这个代码中我们发现一件事,如果要传递这个数组,我们首先要知道数组的位数,但是我们要求的不就是数组的位数吗,这就是上文我们做的,其实也是模板的主要作用:实参演绎,我们规定了两个参数,这两个参数到底谁是5位数组,谁是10位数组,这个工作在模板中被自动的完成了,综合了上述两种技术我们实现了数组的传递
其次,我们需要知道子函数返回的数组的时候也很麻烦,不仅仅因为返回的是指针,更是因为在子函数中定义的数组会随着函数的结束而释放,最终只留下数组头一个数据可以使用,所以我们用动态内存,去主动的分配一个空间给数组
现在我们把操作和方法放在下面:
模板: | 传入一个数组(实现泛型编程,因为要传入的这个数组长度是不确定的) |
引用传递: | 这里没有操作原来的数,仅仅是为了减少拷贝的操作 |
new: | 给数组创建内存 |
delete: | 配合new,释放内存 |
以下代码思路:
先弄两个数组,一起传入到子函数中
由子函数创建新的数组,通过加减法给新的数组赋值,(new)
操作完新的数组之后结束程序(delete)
1 #include<iostream>
2
3 using namespace std;
4
5 template <typename T1,typename T2> //要在模板参数列表中定义两个模板参数;因为:
6 int* plusArr(T1& a,T2& b); //将来传入的int[10]和int[5]是两个不同的类型
7
8 int main(){
9
10 int a[10]={1,2,3,4,5,6,7,8,9,0};
11 int b[5]={3,4,5,6,7};
12
13 int* sum=plusArr(a,b); //用sum保存这个指针,因为plusArr栈会清掉(包括指针p)
14
15 int i=0;
16 while(sum[i]!='\0'){
17 cout<<sum[i]<<' ';
18 ++i;
19 }
20
21 delete[] sum; //释放内存 在此,delete一定要加中括号[]!!
22 }
23
24 template<typename T1,typename T2>
25 int* plusArr(T1& a,T2& b){
26
27 int m=(int)sizeof(a)/sizeof(a[0]);
28 int n=(int)sizeof(b)/sizeof(b[0]);
29
30 if(m>n){
31 int* p=new int[m+1]; //在堆上分配了动态内存 (并未初始化)
32 for(int i=0;i<n;i++){ //开始赋值
33 p[i]=a[i]+b[i];
34 }
35 for(int i=n;i<m;i++){
36 p[i]=a[i];
37 }
38 p[m]='\0'; //用来标志
39 return p;
40 }
41 else{ //上面的是a长度大,下面b同理
42 int* p=new int[n+1];
43 for(int i=0;i<m;i++){
44 p[i]=a[i]+b[i];
45 }
46 for(int i=n;i<m;i++){
47 p[i]=b[i];
48 }
49 p[n]='\0';
50 return p;
51 }
52
53 }
这个函数写出来呢,主要是验证一些函数的用法,这些函数虽然在这个程序中显得“过分”了,但是在将来涉及到复用的时候,像这种泛型编程就可以大显身手,顺便复习一下new delete
更加深入的理解:
在人民邮电出版社《C++模板:tamplate》一书中开头就提醒我们模板的定义一定要写常量引用,而且注意const的顺序一定是在后面;
下面我们列出一个模板的定义,并尝试去理解他的形式参数性质:
1 #include<iostream>
2 int main(){
3 int* b;
4 int* &a=b; //这里对指针a的操作等于直接对指针b进行操作
5
6 int const c;
7 int* const d; //定义一个正常的常量指针d
8
9 int* n;
10 int* const &m=n; //定义一个常量指针的引用,这里n是常量,所有对m的操作最终会作用到n上
11
12 //在模板中我们经常看到如下定义
13 tamplate<typename T>
14 T const& name(T const& a,T const& b){ //这里是引用传递,并且我们不会用引用去更改外面的值
15 ;
16 }
17
18 return 0;
19 }
转载请注明来源
最新文章
- Centos 7 安装 设置 IP地址,DNS,主机名,防火墙,端口,SELinux (实测+笔记)
- Ansible-Tower快速入门-4.以超级用户帐号登录【翻译】
- !!!四种常见的 POST 提交数据方式(含application/json)
- js 使用json.js处理json对象
- 【LeetCode OJ】Best Time to Buy and Sell Stock
- Oracle物化视图,物化视图日志,增量刷新同步远程数据库
- OpenSCAD 建模:矿泉水瓶花洒
- Linux(centos7)下安装Docker
- javascript基础 之 jQuery教程
- 【任务】Python语言程序设计.MOOC学习
- python--爬取豆瓣热门国产电视剧保存为文件
- 『TensorFlow』降噪自编码器设计
- linux中日历命令显示
- Python之路,第三篇:Python入门与基础3
- Hashmap jdk7 死循环
- api重复引用导致的诡异问题排查
- 【LeetCode】114. Distinct Subsequences
- 内存记号(Memory Trail)[自定义的名字] --调试方法
- http://deepdish.io/2015/04/28/creating-lmdb-in-python/
- ORACLE内存结构之SGA
热门文章
- mybatis中association和collection使用
- Java-(array)数组的基本概念 及 Java内存划分
- winform datagridview行头添加序号
- Objects.requireNonNull的意义是什么
- js-day01-商品订单信息
- Maven工程提示 java:源值1.5已过时,将在未来所有发行版中删除 出现原因及解决方案(亲测好用)
- ArcObjects SDK开发 014 MapSurround和普通Element
- 一文带你入木三分地理解字符串KMP算法(next指针解法)
- week_7
- week_3