面向对象程序设计(二):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 }
复制代码

 

转载请注明来源

 

posted @   dou_fu_gan  阅读(134)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示