一、函数的参数及其传递方式

C++的函数传递有两种传递方式:传值和伟引用。传值分为传“对象值”和“对象地址值”,“对象值”是指对象的数据成员值,“对象地址值”是指对象的首地址值。伟引用其实是传对象的地址。

注意:传地址值传递的是值,不是地址;传地址传的是地址,不是地址值。传递对象地址值是使用对象指针作为参数,传递对象地址是使用对象引用作为参数。

1、对象作为函数参数

将对象作为函数参数,是将实参对象的值传递给形参对象,这种传递是单向的。形参拥有实参的备份,当在函数中改变形参的值时,改变的是这个备份的值,不会影响原来实参的值,这种传值方式可以防止被调用的函数改变参数的原始值。

#include <iostream>
#include <string>
using namespace std;
void example1();
void swap1(string,string);//声明交换方法的函数原型
int main(){example1();return 0;
}void example1(){string s1("过去"),s2("现在");//定义对象s1和s2cout << "交换之前:" << s1 << " " << s2 << endl;swap1(s1,s2);//使用传值方式传递s1和s2的数据成员值cout << "交换之后返回主函数:" << s1 << " " << s2 << endl;/*** 交换之前:过去 现在* 交换之后:现在 过去* 交换之后返回主函数:过去 现在*/
}void swap1(string s1,string s2){string temp = s1;s1 = s2;s2 = temp;cout << "交换之后:" << s1 << " " << s2 << endl;
};

2、对象指针作为函数参数

将指向对象的指针作为函数参数,形参是对象指针,实参是对象的地址值。虽然参数传递方式仍然是传值,但因为形参传递的就是实参本身,所以当在函数中改变形参的值时,改变的就是原来实参的值。传对象地址值要用到对象指针,常使用的传对象地址值的方式,如传递类或结构对象的地址值、传递数组名。

void example2();
void swap2(string *,string *);
int main(){example2();return 0;
}void example2(){string s1("过去"),s2("现在");cout << "交换之前:" << s1 << " " << s2 << endl;swap2(&s1,&s2);//使用传地址值的方式传递s1和s2的地址值cout << "交换之后返回主函数:" << s1 << " " << s2 << endl;/*** 交换之前:过去 现在* 交换之后:现在 过去* 交换之后返回主函数:现在 过去*/
}void swap2(string *s1,string *s2){//string类的对象指针s1和s2作为参数string temp = *s1;*s1 = *s2;*s2 = temp;cout << "交换之后:" << *s1 << " " << *s2 << endl;
}

因为实参和形参的地址相同,所以改变形参就是改变实参。下面举例传递数组名:

void example3();
void swap3(int []);
int main(){example3();return 0;
}void example3(){int a[] = {8,3};cout << "交换之前:" << a[0] << " " << a[1] << endl;swap3(a);//传递数组名a也就是传递指针cout << "交换之后返回主函数:" << a[0] << " " << a[1] << endl;/*** 交换之前:8 3* 交换之后:3 8* 交换之后返回主函数:3 8*/
}void swap3(int a[]){//使用数组名a也就是指针名作为函数参数int temp = a[0];a[0] = a[1];a[1] = temp;cout << "交换之后:" << a[0] << " " << a[1] << endl;
}

数组名就是数组指针名,数组指针名指向数组首地址,所以相当于传地址值,可以实现交换。

3、引用作为函数参数

使得引用作为函数,在函数调用时,实参对象名传给形参对象名,形参对象名就成为实参对象名的别名,实参对象和形参对象代表同一个对象,所以改变形参对象的值就是改变实参对象的值。

实际上,在传递地址时,是把实参对象的地址传给形参对象,使用形参对象的地址取实参对象的地址,从而使用形参对象和实参对象共享一个单元,这就是地址传递方式。

void example4();
void swap4(string &,string &);
int main(){example4();return 0;
}void example4(){string s1 = "过去",s2 = "现在";cout << "交换之前:" << s1 << " " << s2 << endl;swap4(s1,s2);//使用传地址的方式传递s1和s2的引用地址cout << "交换之后返回主函数:" << s1 << " " << s2 << endl;/*** 交换之前:过去 现在* 交换之后:现在 过去* 交换之后返回主函数:现在 过去*/
}void swap4(string &s1,string &s2){//string类的引用对象s1和s2作为函数参数string temp = s1;s1 = s2;s2 = temp;cout << "交换之后:" << s1 << " " << s2 << endl;
}

系统向形参传递的是实参的地址而不是实参的值,通过引用参数,一个函数可以修改另一个函数内的变量,因为引用对象不是一个独立的对象,不单独占用内存单元,而对象指针要另外开辟内存单元(其内容是地址),所以传引用比传指针要更好。

4、默认参数

默认参数就是不要求程序设定该参数,而由编译器在需要时给该参数赋默认值,当程序员需要传递特殊值时,必须显式的指明。默认参数是在函数原型中说明的 ,默认参数可以多于一个,但必须放在参数序列的后面。

void example6();
void display1(int first,int second=2,int third=3);
int main(){example6();return 0;
}void example6(){int first = 10,second = 20,third = 30;display1(first);//第一个参数值是:10,第二个参数值是:2,第三个参数值是:3display1(first,second);//第一个参数值是:10,第二个参数值是:20,第三个参数值是:3display1(first,second,third);//第一个参数值是:10,第二个参数值是:20,第三个参数值是:30
}void display1(int first,int second,int third){cout << "第一个参数值是:" << first << ",第二个参数值是:" << second << ",第三个参数值是:" << third <<endl;
}

5、使用const保护数据

用const修饰传递参数,是通知函数,它只能使用参数而无权修改它。

void display2(const string &,string &);

二、深入讨论函数返回值

1、返回对象的函数

void example7();
string back1(string);
int main(){example7();return 0;
}void example7(){string s = "zhangsan";string ss = back1(s);cout << ss;//zhangsanfeng
}string back1(string s1){string s2 = s1 + "feng";return s2;
}

2、返回指针的函数

void example8();
float * back2(int &);
int main(){example8();return 0;
}void example8(){int num;float *f;f = back2(num);for(int i=0;i<num;i++){cout << "值" << (i+1) << "是:" << *(f+i) << endl;}delete f;
//  3
//  你要输入的数值个数是:3个
//  10.3 12.5 16.7
//  值1是:10.3
//  值2是:12.5
//  值3是:16.7
}float * back2(int &num){cin >> num;cout << "你要输入的数值个数是:" << num << "个" << endl;if(num <= 0){return NULL;}float *f = new float[num];//动态申请分配内存if(f == 0){return NULL;}for(int i=0;i<num;i++){cin >> f[i];}return f;
}

3、返回引用的函数

函数可以返回一个引用,返回引用的主要目的是为了将该函数用在赋值运算符的左边。在其他情况下,一个函数是不能直接用在赋值运算符左边的。

void example9();
int &back3(int);
int arr2[] = {10,20,30};//声明全局数组
int main(){example9();return 0;
}void example9(){int index = 2;cout << "修改之前:" << arr2[index] << endl;//修改之前:30back3(index) = 100;cout << "修改之后:" << arr2[index] << endl;//修改之后:100
}int &back3(int num){return arr2[num];
}

4、函数返回值作为函数的参数

void example10();
int back4(int,int);
int main(){example10();return 0;
}void example10(){int max = back4(10,back4(55,102));cout << max;//102
}int back4(int i,int j){int max = i>j?i:j;return max;
}

三、内联函数

① 使用关键字inline可以让C++编译器在遇到对函数isnumber调用的时候,都用这个函数体替换调用表达式;

② 由于编译器必须知道内联函数的函数体,才能进行内联替换,因此内联函数必须在程序中第一次调用此函数的语句出现之前定义;

③ 如果程序多次调用某个函数,将会大大降低使用效率,使用内联函数能加快程序执行速度;

④ 具有循环语句、switch语句的函数不能说明为内联函数。

void example11();
inline int isnumber(char c){return (c>='0'&&c<='9')?1:0;
}
int main(){example11();return 0;
}void example11(){char c;cin >> c;if(isnumber(c)){cout << "你输入的是一个0-9之间的数字!" << endl;}else{cout << "你输入的不是一个数字!" << endl;}//    0
//  你输入的是一个0-9之间的数字!
}

四、函数重载和默认参数

函数重载可使一个函数名具有多种功能,即具有“多种形态”,这种特性被称为多态性。C++的多态性被直观的称为“一个名字,多种函数”,即每个函数除了函数名相同外,其他的都不相同。这时源代码只指明函数调用,而不说明具体调用哪个函数,编译器的这种连接方式称为动态联编,在动态联编中,只有程序运行时才能确定调用哪个函数。

如果编译器在编译时,能根据源代码调用固定的函数标识符,并用物理地址替代它们,这就称为静态联编,静态联编是在程序被编译时进行的。

void example12();
float max(float,float);//具有两个实型参数的函数原型
int max(int,int,int);//具有两个整型和一个实型参数的函数原型
int main(){example12();return 0;
}void example12(){cout << "请输入两个实型数:" << endl;float f,g;cin >>f,cin>>g;float ff = max(f,g);cout << f << "和" << g << "中最大的实型数是:" << ff << endl;cout << "请输入三个整数:" << endl;int i,j,k;cin >>i,cin>>j,cin>>k;int ii = max(i,j,k);cout << i << "、" << j << "、" << k << "中最大的整数是:" << ii << endl;
}float max(float f,float g){return f>g?f:g;
}int max(int i,int j,int k){int temp = i>j?i:j;return temp>k?temp:k;
}

五、函数模板

1、引入函数模板

以求两个数的最大值为例,区别仅仅是处理的数据类型不同,这时可以把它们的操作进行抽象,比如:Type max(Type n1,Type n2){return n1>n2?n1:n2;}。这里Type并不是一种实际的数据类型,而是使用虚拟的类型参数,当用实际的类型来实例化这种函数时,就好像按照模板来制造新的函数一样,所以称这种函数为函数模板。将函数模板与某个具体的数据类型连用,就产生了模板函数,这个过程被称为模板函数实例化,这种形式就是类型参数化。

一般选用T作为标识符来标识类型参数,当然参数名是可以任意挑选的,不一定非得是T。规定模板以template关键字和一个形参表示开头。可以写成如下形式:

template <class T> T max(T n1,T n2){return n1>n2?n1:n2;
}

class意为“用户定义或固有的类型”,字母T标识这个模板有一个参数类型,模板的参数是由函数的参数类型推断出来的。

void example13();
template <class T> T max2(T n1,T n2){return n1>n2?n1:n2;
}
int main(){example13();return 0;
}void example13(){cout << max2(10,25) << " " << max2(25.5,10.2) << " " << max2('a','b') << endl;//25 25.5 b
}

2、使用显式规则和关键字typename

关键字typename主要用于替代参数列表中的关键字class。下面是使用显式规则和关键字typename的例子:

void example14();
template <typename T> T max3(T n1,T n2){//求最大值的函数模板return n1>n2?n1:n2;
}
template <typename E> E max4(E n1,E n2){//求最小值的函数模板return n1<n2?n1:n2;
}
int main(){example14();return 0;
}void example14(){cout << max3(10,(int)18.2f) << " " << max3 <double>(10.3,20.5) << endl;//使用强制转换以及显式声明求最大值,18 20.5cout << max4(10,50) << " " << max4 <int>(8.1,15.3) << endl;//使用显式声明可以用于一些特殊需求,10 8
}

C++程序设计(三)—— 函数和函数模板相关推荐

  1. c++ 函数模板_C/C++编程笔记:C++入门知识,深入解析C++函数和函数模板

    本篇要学习的内容和知识结构概览 函数的参数及其传递方式 1. 函数参数传递方式 传值: 传变量值: 将实参内存中的内容拷贝一份给形参, 两者是不同的两块内存 传地址值: 将实参所对应的内存空间的地址值 ...

  2. C++笔记函数重载函数模板

    #include <iostream>using namespace std;class Student { private:int num;int score; public:void ...

  3. matlab实验函数编写与程序设计,matlab实验四函数编写与程序设计.doc

    实验四:函数编写与程序设计 一.实验目的1 . 掌握M文件的创建. 2.掌握函数的编写规则. 3.掌握函数的调用. 4 . 掌握基本的输入输出函数以及显示函数的用法. 5.会用Matlab程序设计实现 ...

  4. 《Python数据分析基础教程:NumPy学习指南(第2版)》笔记8:第三章 常用函数4——线性模型、数组修剪与压缩、阶乘

    本章将介绍NumPy的常用函数.具体来说,我们将以分析历史股价为例,介绍怎样从文件中载入数据,以及怎样使用NumPy的基本数学和统计分析函数.这里还将学习读写文件的方法,并尝试函数式编程和NumPy线 ...

  5. ES6-ES11-第一部分-let、const、解构赋值、模板字符串、简化对象写法、箭头函数、函数参数默认值、rest 参数、扩展运算符、Symbol、迭代器、生成器、Promise、Set、Map

    根据视频进行整理 [https://www.bilibili.com/video/BV1uK411H7on?p=1] 视频资源(百度网盘): 链接:[https://pan.baidu.com/s/1 ...

  6. 计算机函数公式发生额总计,如何用Excel Sumif函数做查询模板统计客户在不同时间借款的总金额...

    一个客户在不同时间借款好几笔,如何能知道他一次借款的金额?能直接查看吗?可以直接显示他总的借款金额呢?这个问题是一个网友提出的,可以看的到,连续用了三个问号.这个问题的解决方法有很多种,本教程给出的方 ...

  7. Python基础(三)_函数和代码复用

    三:函数和代码复用 (一)函数的基本使用 1.函数的定义 函数是一段具有特定功能的.可重用的语句组,用函数名来表示并通过函数名进行功能调用.函数也可以看作是一段具有名字的子程序,可以在需要的地方调用执 ...

  8. day 53-1 Django基础三之视图函数

    Django基础三之视图函数 本节目录 一 Django的视图函数view 二 CBV和FBV 三 使用Mixin 四 给视图加装饰器 五 Request对象 六 Response对象 一 Djang ...

  9. C语言设计函数求最大公约数,C语言程序设计课程设计--编写函数求取两个整数m,n的最大公约数和最小公倍数.doc_在线文库www.lddoc.cn...

    C语言程序设计课程设计--编写函数,求取两个整数m,n的最大公约数和最小公倍数.doc C语言程序设计课程设计C语言程序设计课程设计评语考勤(10)纪律(10)过程(40)设计报告(30)答辩(10) ...

最新文章

  1. 在CentOS 6.3 64bit上安装Apache Trafficserver 4.2.3挂载SAS硬盘和SSD
  2. 被骂了三年,谷歌Dropout专利还是生效了,卡脖子预警
  3. 初看Mybatis 源码 (二) Java动态代理类
  4. codeforce 154C - Double Profiles(hash)
  5. java string 返回匹配正则的字符串的起始位置_Python小课堂正则表达式
  6. Linux系统里如何重装ibus,Linux下安装ibus-rime的方法
  7. 带你了解数据库的“吸尘器”:VACUUM
  8. python使用HanLP命名实体识别(以识别人名为例)
  9. window.location.href跳转无效 IE Bug【转载】
  10. IntelliJ IDEA 自定义控制台输出多颜色格式功能 --- 安装Grep Console插件
  11. 深入了解STL中set与hash_set,hash表基础
  12. iis php 知乎,设置 | WeCenter创建你的知乎
  13. 抖音大数据,教你爬爬爬!
  14. 求不大于N的最大质数
  15. AT91SAM9260搭建LINUX操作系统
  16. 泛泰A870L/K/S第三版官方4.4.2原来的系统卡刷机包 (愿自己主动ROOT)
  17. 计算机技术专硕学哪些课程,计算机专业考研需要考哪些科目
  18. Spark吐血整理,学习与面试收藏这篇就够了!
  19. java 时间计算差值
  20. VLAN Switch

热门文章

  1. oracle 误删除表数据,Oracle误删除表数据后的数据恢复详解
  2. 改装版 hiwifi 1S 路由器
  3. 中国证券报:神州信息加强农业农村场景金融创新 助推金融“活水”下乡
  4. google 进入分屏后在横屏模式按home键界面错乱( 四) 分屏的转屏过程
  5. 趣讲用c语言实现三子棋小游戏
  6. Shopee折扣设置起来,让你的虾皮店铺成为焦点
  7. 育英小学参加计算机班,育英小学德景园分校、北师大新标准体系幼儿园开工仪式隆重举行...
  8. 康颐杂志康颐杂志社康颐编辑部2022年第24期目录
  9. 登山的过程总是艰难的
  10. 利用OpenCV实现图像纹理特征提取