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

C++函数三剑客:缺省参数·函数重载·引用的高效编程指南

前引:在C++编程中,缺省参数、函数重载、引用是提升代码简洁性、复用性和效率的三大核心机制。它们既能减少冗杂的代码,又能增强接口设计的灵活性。本文将通过清晰的理论解析与实战案列,带你深入理解这三者的设计思想、使用场景以及闭坑指南~

【注:由于内容平均排版,引用的结尾特安排在下一篇!】

目录

缺省参数

何为缺省参数

全缺省参数

 半缺省参数

不缺省参数

注意 

函数重载

何为函数重载

参数个数不同

参数类型不同

 类型顺序不同

注意 

为何C++支持函数重载,而C不支持

引用

什么是引用

引用的使用

一级指针的变化:

二级指针的变化:

​编辑

语法注意:

一级指针函数的变化:

 二级指针函数的变化:

​编辑​编辑

语法注意:

引用的指针的优劣

 优先使用引用的场景:

必须使用指针的场景:

关于引用返回值的讲解


缺省参数

何为缺省参数

允许函数在声明时指定默认值,调用函数时可以省略部分参数。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。例如:

Func();//没有传参使用参数的默认值
Func(10);//传参了使用指定的参数

全缺省参数

顾名思义,全缺省参数就是所有参数全部都额外指定,例如:

	Func();Func(1,2,3);//与参数个数无关

 半缺省参数

半缺省位于全缺省 和 不缺省之间,也比较好理解,比如:

Func();
Func(1,3);(与参数个数无关)

不缺省参数

所有参数都不额外指定,例如:

Func(1,2,3);//缺不缺省与参数个数无关
Func(1,2);
Func(1);

注意 

这样看来我们的参数指不指定似乎是随机的!但是,它有语法规则限制:

 默认参数必须从右往左连续设置(默认参数可以是常量、全局变量、函数返回值....但不能是局部变量),例如:

参数必须从右往左连续设置的几种情况:

(1)传参顺序错误

 (2)函数参数顺序错误

(3)声明与定义只能选择一个设置函数缺省,否则就会报错

(4)缺省只有.cpp文件支持,在纯c的.c文件中不支持

函数重载

何为函数重载

是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题

参数个数不同

参数个数指的是传参的个数,不是函数接收的参数

参数类型不同

函数参数接收的类型可以不同,例如:

void Func(int a=5,int b=10,int c=10)
{std::cout << a + b + c << std::endl;
}void Func(double a = 5, double b = 10, double c = 10)
{std::cout << a + b + c << std::endl;
}

同时,参数类型可以不用统一,只要保证函数名相同就行,例如:

void Func(int a=5,int b=10,int c=10)
{std::cout << a + b + c << std::endl;
}void Func(double a = 5, double b = 10, double c = 10)
{std::cout << a + b + c << std::endl;
}void Func(double a = 5, double b = 10, int c = 10)
{std::cout << a + b + c << std::endl;
}

 类型顺序不同

这点其实和刚才的参数类型不同很相似,我们直接看:

void Func(double a=5,int b=10,int c=10)
{std::cout << a + b + c << std::endl;
}void Func(double a = 5, double b = 10, int c = 10)
{std::cout << a + b + c << std::endl;
}

注意 

(1)需要注意的是,函数传参跟声明个数是匹配的

比如它不会去自动识别你想匹配哪个函数。两个函数传参,对应两个函数接收

(2)如果只有返回值不同是不构成重载的,因为编译器无法根据参数是判断是不是构成重载 

为何C++支持函数重载,而C不支持

首先不论是C还是C++,从代码->展示效果都会经历这几个阶段:

 既然这个过程是一样的,那么它们之间必定在某个阶段有所差别:

小编认为可以这么总结:

假如我现在缺钱,想找某个人借,那么C借给我 跟 C++借给我的方式是不一样的!

在C中的编译阶段,根据函数定义直接兑现承诺,根据函数定义直接去替换成对应的函数,那么当再次调用这个函数,发现跟之前的不一样了,就会报错。比如 C 直接借给你钱!

在C++中的编译阶段,根据函数声明先承诺,根据函数的声明生成不同的函数类型,因此可以存在多个同名的函数,此时同名不代表是同一个函数。C++ 会先答应借给你,并不是直接借给你钱!

引用

什么是引用

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空 间,它和它引用的变量共用同一块内存空间

引用是可以赋值给变量的,俗称为“引用变量”,例如:从可以赋值来看,我们看到 pc 并不是指针

int tmp = 10;int& pc = tmp;
int cur = pc;

形象比喻:比如李逵,江湖上叫“黑旋风”,他也叫“铁牛”,这三个称呼是同一个人,你叫其中的某一个称呼,叫的其实是同一个对象

引用的使用

学了C++中的引用之后,你会发现C++中的指针使用与C中的指针使用有很大的变化,更简洁

例如常见的几种C中指针用法:

 C++中学了引用之后,我们可以这么改进,下面我们分开对比,否则不好理解!

一级指针的变化:
	//设置变量int tmp = 10int& cur = tmp;//C++cur = 30;;

我们可以看到,C++引用到一级指针中去,可以不用去解引用了,直接通过变量访问

二级指针的变化:

在C中我们的二级指针是指向一级指针地址的

在C++引用中,引用的对象同样是一级指针,不是变量本身哦!(牢记),例如:

    //二级指针引用int*& coun = p;//C++*coun = 100;

解释:coun是p的引用二者地址相同,操作的也就是p,*coun操作的也就是*p,*p也就是tmp本身 

这里需要注意:C++二级指针引用还是需要指向一级指针,因为二级指针的定义是:二级指针指向一级指针地址 ,只是这里不需要去给 p 加上取地址

语法注意:

C指针:

(1)可以不对指针进行初始化,但是有野指针的风险

(2)可以对指针进行赋值,比如为 NULL,或者指向其它变量或指针

(3)使用时操作变量需要解引用*,在函数里面->才能访问成员

例如:

//可以不初始化
int* p;
//可以赋值
int* p = NULL;
//需要解引用访问
*p = 20;

C++引用:

(1)必须初始化,且绑定后不可以重新绑定

(2)无空引用,始终指向有效的对象

(3)直接通过引用名访问,无需解引用

例如:

	int tmp = 10;//必须初始化int& pc = tmp;//无空引用,始终指向有效对象int& cur = NULL;//直接通过引用名访问,无需解引用pc = 20;
一级指针函数的变化:

首先是传参,传指向对象 或者 指针命名对象都是可以的,它们的接收参数形式是统一的

就仿佛:我给“铁牛”沏一杯茶,和我给“黑旋风”沏一杯茶,对象是同一个人 

Func(pc);Func(tmp);

 二级指针函数的变化:

都需要传二级指针,它们的传参对象都指向同一个 (一级指针地址 与 引用对象同址),例如下面的 pcur同址

Func(cur);Func(p);
语法注意:

(1)强制初始化,且无法为空,杜绝引用错误

//杜绝为空
int& pc;//必须绑定对象
int tmp;
int& cur = tmp;

(2)严格匹配类型,无法隐式转换

int tmp = 10;
//严格匹配类型,无法隐式转换
double& pc = tmp;

(3)C++引用二级指针需要指向一级指针,这个一级指针不能是C++引用类型 

//设置变量
int tmp = 10;//一级指针
int* pc = &tmp;
int& cur = tmp;//二级指针
//不能使用C++一级指针引用对象
int*& pc = cur;//错误语法
int*& pc = pc;//正确语法
引用的指针的优劣

两者在运行性能上几乎一致,但引用通过语法减少了潜在的错误,提高了代码的健壮性

(1)引用概念上定义一个变量的别名,指针存储一个变量地址

(2)引用在定义时必须初始化,指针没有要求

(3)引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何           一个同类型实体

(4)没有NULL引用,但有NULL指针

(5)在 sizeof 中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数                (32位平台下占4个字节)

(6)引用自加即引用的实体增加 1 ,指针自加即指针向后偏移一个类型的大小

 优先使用引用的场景:

(1)函数参数传递

(2)操作符重载

(3)返回值

必须使用指针的场景:

(1)动态内存管理

(2)与C库交互,比如调用 printf 或C标准库函数时

(3)可选参数或者多态

关于引用返回值的讲解

首先我们看一个错误例子,这是将一个引用变量赋值给另一个变量 ret

首先:这里的打印虽然是“1”,但是它的打印值其实是不固定的,有以下两种情况:

(1)如果Func函数结束,栈帧销毁,没有清理栈帧,那么 ret 的结果侥幸是正确的

(2)如果Func函数结束,栈帧销毁,,清理了栈帧,那么 ret 的结果就是随机的

例如下面:普通函数可以通过中间变量赋值带回,引用没有中间变量,销毁了也就无法返回值了

我们的解决方案有以下两种:

(1)使用全局变量 或 静态变量,如:int n  ->  static int n

原因:当使用 static 修饰局部变量时,变量的周期会持续到整个程序结束,即函数调用完也不会               被销毁

int& Func()
{static int n = 0;//修改方式1n++;return n;
}int main()
{int ret = Func();std::cout << ret << std::endl;return 0;
}

(2)改返回值,而非引用,如:int& Func()->  int Func()

原因:修改之后只是一个简单的赋值,不与引用规则发生冲突

int Func()//修改方式2
{int n = 0;n++;return n;
}int main()
{int ret = Func();std::cout << ret << std::endl;return 0;
}

所以在使用引用做返回值时,需要特别注意该函数的生命周期,引用的使用是很活跃的! 

【雾非雾】期待与你下次相遇! 

相关文章:

  • Electron入门指南:用前端技术打造桌面应用
  • 更换git位置并在pycharm中重新配置
  • LeetCode 题解 41. 缺失的第一个正数
  • CycleISP: Real Image Restoration via Improved Data Synthesis通过改进数据合成实现真实图像恢复
  • 详细说说Spring的IOC机制
  • 注解和 XML 两种方式有什么区别?
  • 单调栈简单习题分析
  • 【免杀】C2免杀技术(三)shellcode加密
  • 深度学习中.cuda()、.eval()与no_grad详解
  • 深度学习入门:卷积神经网络
  • 解密企业级大模型智能体Agentic AI 关键技术:MCP、A2A、Reasoning LLMs-强化学习算法AlphaGo
  • NeurIPS Paper Checklist中文翻译
  • 如何下载和安装 Ghost Spectre Windows 11 24H2 PRO
  • CD38.【C++ Dev】string类的模拟实现(2)
  • 深入理解卷积神经网络:从基础原理到实战应用
  • 2025年道路运输安全员考试题库及答案
  • vulnhub靶场——secarmy
  • Python知识框架
  • SSH秘钥配置介绍
  • 44、私有程序集与共享程序集有什么区别?
  • 陕西河南山西等地将现“干热风”灾害,小麦产区如何防范?
  • 新能源汽车,告别混乱创新
  • 落实中美经贸高层会谈重要共识,中方调整对美加征关税措施
  • 联合国秘书长欢迎中美经贸高层会谈成果
  • 中央结算公司:减免境外央行类机构账户开户费用
  • 文学花边|对话《借命而生》原著作者石一枫:我给剧打90分