当前位置: 首页 > news >正文

day44——C++对C的扩充

八、C++对函数的扩充

8.1 函数重载(overload)

1> 概念

函数重载就是能够实现"一名多用",是实现泛型编程的一种

泛型编程:试图以不变的代码,来实现可变的功能

2> 引入背景

程序员在写函数时,可能会出现这种情况:定义多个函数时,仅仅只是因为函数参数的类型不同或者函数参数个数的不同,导致同一个功能的函数需要定义多个不同名字。例如:两个整数求和、两个小数求和、三个整数求和。。。这些都只是实现求和功能,由于参数个数或参数类型的不同,就需要定义多个函数名字,用起来比较麻烦。

基于以上背景,C+引入了函数重载:运行在同一个作用域下,定义多个同名的函数。但是,要求这些同名的函数必须参数参数不同,后期调用时,系统会根据主调函数的实参去自动匹配相应的函数执行。

3> 要求:

函数名相同

形参列表必须不同

返回值无关

必须在同一个作用域下

#include <iostream>using namespace std;//定义两个整数的求和
int sum(int m, int n)
{return m+n;
}//下面这个函数会报错,即使函数返回值和函数体内容不同,也不能构成重载
//void sum(int m, int n)
//{
//    return m-n;
//}//定义两个小数的求和
float sum(float m, float n)
{return  m+n;
}//定义两个double类型的数据求和
double sum(double m, double n)
{return m+n;
}//定义三个整数的求和
int sum(int m, double n, int k)
{return m+n+k;
}int main()
{cout<<sum(3,7)<<endl;        //10cout<<sum(3.5,7.5)<<endl;        //11cout<<sum(3,7.5, 6)<<endl;   //16return 0;
}练习:定义函数分别求两个整数的最大值,两个小数的最大值,三个整数的最大值,并验证
Plain Text
自动换行#include <iostream>using namespace std;
//定义两个整数的求和
void max(int m,int n)
{if(m>n){cout<< m <<"大" <<endl;}else{cout<< n <<"大" <<endl;}
}
//定义两个double小数的求和
void max(double m,double n)
{if(m>n){cout<< m <<"大" <<endl;}else{cout<< n <<"大" <<endl;}
}
void max(int m,int n,int k)
{if(m>n){if(m>k){cout<< m <<"大" <<endl;}else{cout<< k <<"大" <<endl;}}else{if(n>k){cout<< n <<"大" <<endl;}else{cout<< k <<"大" <<endl;}}
}
int main()
{max(3,7);max(1.12,2.22);max(1,2,3);max(1,3,3);return 0;
}

8.2 函数的默认参数

1> 引入目的:

程序员在定义函数时,可能会出现一个功能出现多个参数,但是,有时候,只需要传递其中某几个参数即可执行。此时,主调函数中传过来的参数,被调函数使用传过来的,主调函数没传过来的参数,被调函数使用自己的默认值

2> C++允许在定义函数时,给其中的某几个参数设置默认参数,对于设置了默认值的参数,主调函数传数据就使用主调函数传的,主调函数不传数据,就使用默认值

3> 默认参数的设置原则:靠右原则,也就是说必须当前参数的右边的形参设置了默认值后,当前参数才能设置默认值。

原因是,函数参数传递的过程是靠左原则,实参向形参传递时,向给左侧的形参赋值

4> 当函数重载和默认参数同时出现时,注意,如果带默认参数的函数包含了重载的函数,那么函数定义时没有问题,但是函数版调用时会不确定调用哪一个

5> 如果带默认参数的函数,声明和定义分开时,默认参数写在声明部分,定义部分就不写默认参数了

#include <iostream>using namespace std;int sum(int  = 0, int =0, int =100);    //函数声明//定义重载函数时
//int sum(int x, int y):如果有默认参数包含了该函数,函数定义是没有问题,但是函数调用时会不知道调用哪一个
int sum(int x, double y)
{return x+y;
}int main()
{cout << sum(2,3,5) << endl;       //调用了默认参数的函数,三个参数主调函数传递cout << sum(2,3) << endl;       //调用了默认参数的函数,前两个参数主调函数传递,后一个参数使用默认的cout << sum(2) << endl;       //调用了默认参数的函数,前一个参数主调函数传递,后两个参数使用默认的cout << sum() << endl;        //调用了默认参数的函数,三个参数使用的都是默认值return 0;
}//函数定义在被调函数后面
int sum(int m , int n, int k)
{return m+n+k;
}

8.3 哑元

1> C++定义函数时,支持哑元,运行某个形参或某几个形参只有声明,没有实际意义,唯一的作用就是起到占位作用

#include <iostream>using namespace std;//该函数中的参数2就是一个哑元,只起到占位作用,不让程序优化后报错
int sum(int m, int, int k)
{return m+k;
}int main()
{cout << sum(2,3,5) << endl;cout << sum(2,3,5) << endl;cout << sum(2,3,5) << endl;cout << sum(2,3,5) << endl;cout << sum(2,3,5) << endl;cout << sum(2,3,5) << endl;cout << sum(2,3,5) << endl;cout << sum(2,3,5) << endl;cout << sum(2,3,5) << endl;cout << sum(2,3,5) << endl;cout << sum(2,3,5) << endl;cout << sum(2,3,5) << endl;return 0;
}

2> 使用场景1:当某个程序已经发布后,随着技术的升级,可能会对某些函数进行优化,将原本有多个参数的函数,只需要少了的参数就可以完成,但是此时,未优化前的函数已经被多次调用,修改起来不方便,此时就可以在定义函数时,将被优化掉的形参设置成哑元,只起到接受数据的作用,并不起实际作用

3> 使用场景3:后期学习自增自减运算符重载时,用于区分前置和后置

8.4 内联函数

1> C++支持内联函数,使用关键字inline在函数定义前使用

2> 作用:被设置成内联函数的函数,在编译时,编译器会建议将内联函数自动展开,无需在运行时为该函数开辟内存空间,提高程序的执行效率

3> 内联函数的设置要求:

1、函数体积要小

2、调用比较频繁的函数

3、递归函数不能设置成内联函数

4、不足:如果大量使用内联函数,会使得主程序体积膨胀

#include <iostream>using namespace std;//该函数中的参数2就是一个哑元,只起到占位作用,不让程序优化后报错
inline int sum(int m, int, int k)
{return m+k;
}int main()
{cout << sum(2,3,5) << endl;cout << sum(2,3,5) << endl;return 0;
}

4> 内联函数与带参宏的区别

在C++中,内联函数和带参宏虽然都可以用来在编译时展开代码以减少函数调用的开销,但它们之间存在几个关键的区别:
1. 类型检查
内联函数:内联函数是真正的函数,支持类型安全,会进行类型检查。
带参宏:宏只是预处理器的文本替换工具,不进行类型检查,容易引发类型相关的错误。
2. 编译器优化
内联函数:内联函数允许编译器进行更多优化,比如常量折叠、死代码消除等。
带参宏:宏展开后的代码通常不会受到这些优化的好处,因为它们在预处理阶段就已经被处理了。
3. 调试
内联函数:在调试时,内联函数可以像普通函数一样进行单步调试。
带参宏:宏在预处理阶段就已经被展开,这使得调试变得困难,因为它们在源代码中不再是独立的实体。
4. 作用域
内联函数:内联函数遵循正常的作用域规则。
带参宏:宏没有作用域的概念,它们可以在定义后的任何地方被展开,有时会导致意外的名字冲突。
5. 重复代码
内联函数:内联函数的代码在多个调用点展开时,编译器可以智能地处理,避免不必要的代码膨胀。
带参宏:宏每次使用时都会文本上的复制粘贴,可能会导致代码膨胀。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Spring(面试篇)
  • Linux:SQLite 数据库
  • #QT 笔记一
  • Linux实操笔记1 向服务器出发:连接和登录
  • 大模型LLM的Token相关问题:模型不同,token计算不同,gpt对token的计算,我们如何选择token及token评估模型
  • APP自动化测试思路整理,跟着步骤快速撸码...
  • 建筑企业数字信息化转型的建议
  • 第八周:机器学习
  • ArcGIS中怎么批量计算多个点到线最近距离,以及这些点到线的纬度差?
  • 大模型企业应用落地系列六》基于大模型的对话式推荐系统》推荐引擎层
  • 最大子段和
  • 高频面试题:SpringMVC的执行流程
  • 金9银10跳槽季,最新自动化测试面试题合集
  • MySQL死锁问题解决方案
  • 一本读懂数据库发展史的书
  • Android 架构优化~MVP 架构改造
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • exports和module.exports
  • learning koa2.x
  • open-falcon 开发笔记(一):从零开始搭建虚拟服务器和监测环境
  • Otto开发初探——微服务依赖管理新利器
  • REST架构的思考
  • SpiderData 2019年2月25日 DApp数据排行榜
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 多线程事务回滚
  • 技术:超级实用的电脑小技巧
  • 如何使用 JavaScript 解析 URL
  • 使用 5W1H 写出高可读的 Git Commit Message
  • 视频flv转mp4最快的几种方法(就是不用格式工厂)
  • 用Visual Studio开发以太坊智能合约
  • 原生JS动态加载JS、CSS文件及代码脚本
  • 怎么把视频里的音乐提取出来
  • ​1:1公有云能力整体输出,腾讯云“七剑”下云端
  • # linux 中使用 visudo 命令,怎么保存退出?
  • #java学习笔记(面向对象)----(未完结)
  • (1) caustics\
  • (iPhone/iPad开发)在UIWebView中自定义菜单栏
  • (TipsTricks)用客户端模板精简JavaScript代码
  • (博弈 sg入门)kiki's game -- hdu -- 2147
  • (力扣记录)1448. 统计二叉树中好节点的数目
  • (每日一问)计算机网络:浏览器输入一个地址到跳出网页这个过程中发生了哪些事情?(废话少说版)
  • (四)TensorRT | 基于 GPU 端的 Python 推理
  • (杂交版)植物大战僵尸
  • (转)linux自定义开机启动服务和chkconfig使用方法
  • ./configure,make,make install的作用
  • .gitignore不生效的解决方案
  • .NET Core引入性能分析引导优化
  • .net mvc部分视图
  • .net on S60 ---- Net60 1.1发布 支持VS2008以及新的特性
  • .NET 漏洞分析 | 某ERP系统存在SQL注入
  • .net(C#)中String.Format如何使用
  • .NET是什么
  • .NET中的Event与Delegates,从Publisher到Subscriber的衔接!
  • @Transactional注解下,循环取序列的值,但得到的值都相同的问题