C++入门--缺省、函数重载、引用学习

news2024/12/27 14:34:30

1.缺省参数

1.1缺省参数概念

缺省参数是指在声明或定义函数时为函数的参数指定一个缺省值,如果在调用该函数的时候没有指定参数,函数会使用该参数的缺省值,否则使用指定的参数。

#include<iostream>
using std::cout;
using std::cin;
using std::endl;
void Func(int a=0)
{
	cout << a << endl;
}
int main()
{
	Func();//没有传参数,使用缺省参数
	Func(10);//使用指定参数
	return 0;
}

代码运行的结果为:
在这里插入图片描述

1.2缺省参数分类

全缺省参数

void Func(int a = 10, int b = 20, int c = 30)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
}

半缺省参数

#include<iostream>
using namespace std;
void Func(int a, int b = 20, int c = 30)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
}

使用半缺省参数,必须传值给没有缺省值的参数,否则会报错。

在这里插入图片描述

注意: 1.半缺省参数必须从右向左给出,也不能间隔着给,因为函数是从左往右传参的。

错误的例子:

#include<iostream>
using namespace std;
void Func(int a = 10, int b, int c = 30)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
}
int main()
{
	Func(10);
	return 0;
}

代码运行的结果为:
在这里插入图片描述
2.缺省参数不能在函数声明和定义中同时给出,声明给缺省参数,定义则不给。

在预处理阶段头文件会展开,函数声明会出现在文件中,到编译阶段的时候,会进行检查。如果你使用的函数没有传参,同时声明的函数中的参数不是缺省参数,编译器会报错,如果声明和定义中同时出现缺省参数,恰巧两个位置参数的缺省值不同,编译器无法确定用哪个缺省值。

3.缺省值必须是常量或者全局变量
4.C语言不支持(某些编译器不支持)

使用缺省参数的好处,比如在建立顺序栈的时候,不知道要插入多少个数据的时候,可以使用缺省参数,同时可以建立不同空间大小的顺序栈

2.函数重载

2.1函数重载的概念

函数重载:C++允许在同一作用域中申明几个功能类型的同名函数,这些同名函数的形参列表(参数个数或类型或类型顺序)不同,可以解决功能类似功能不同的函数问题。

参数类型不同

1.参数类型不同
#include<iostream>
using namespace std;
int Add(int left, int right)
{
	cout << "int Add( int left,int right)" << endl;
	
	return left + right;
}
double Add(double left, double right)
{
	cout << "double Add(double left, double right)" << endl;

	return left + right;
}
int main()
{
	cout << Add(1, 2) << endl;
	cout << Add(1.1, 2.2) << endl;
	return 0;
}

代码运行的结果为:
在这里插入图片描述

2.参数个数不同

#include<iostream>
using namespace std;
void Func()
{
	cout << "void Func()" << endl;
}
void Func(int a)
{
	cout << "void Func(int a)" << endl;
}
int main()
{
	Func();
	Func(10);
	return 0;
}

代码运行的结果为:
在这里插入图片描述

3.参数顺序不同

#include<iostream>
using namespace std;
void f(int a, char b)
{
	cout << "void f(int a, char b)" << endl;
}
void f(char b, int a)
{
	cout << "void f(char b, int a)" << endl;
}
int main()
{
	f(10, 'a');
	f('a', 10);
	return 0;
}

代码运行的结果为:
在这里插入图片描述
4.如果仅仅是返回值不相同,不构成重载(编译器不能通过),调用歧义

#include<iostream>
using namespace std;
void Add(int x, int y)
{
	cout << "void Add(int x, int y)" << endl;
}
int Add(int x, int y)
{
	cout << "int Add(int x, int y)" << endl;
}
int main()
{
	Add(1, 2);
	return 0;
}

代码运行的结果为:
在这里插入图片描述
函数重载和缺省参数,在无参调用时存在歧义

#include<iostream>
using namespace std;
void Func()
{
	cout << "void Func()" << endl;
}
void Func(int a = 1)
{
	cout << "void Func(int a = 1)" << endl;
}
int main()
{
	Func();
	return 0;
}

代码运行的结果为:
在这里插入图片描述

函数重载的原理

首先我们知道,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接

预处理:头文件展开\宏替换、删除注释等,生成.i为后缀的文件
编译:检查语法是否正确,生成汇编代码,生成.s为后缀的文件
汇编:汇编代码转化为二进制代码,生成.o为后缀的文件
链接:合并符号表,生成.exe的可执行程序

//game.h
#include<iostream>
using namespace std;
int Add(int left, int right);
double Add(double left, double right);
//game.c
#include"game.h"
int Add(int left, int right)
{
	cout << "int Add( int left,int right)" << endl;

	return left + right;
}
double Add(double left, double right)
{
	cout << "double Add(double left, double right)" << endl;

	return left + right;
}
//test.c
#include"game.h"

int main()
{
	cout << Add(1, 2) << endl;
	cout << Add(1.1, 2.2) << endl;
	return 0;
}

编译阶段:
在这里插入图片描述

1.使用同名函数,在编译的时候,编译器通过参数不同来修饰函数名
2.在链接的时候,通过修饰后的函数名在符号表中找到相应的地址,从而做到对同名函数的调用
3.不是所有函数都需要链接,当定义函数和调用在同一个文件的时候,会直接给相应地址
4.修改的是符号表的函数名

总结: C语言不支持函数名修饰规则,无法对同名函数进行区分,所以不支持重载;C++可以通过函数名修饰规则在编译的时候,会对同名函数进行修改,使编译器可以区分同名函数支持重载,至于函数名的修饰规则,则取决于不同的编译器。

3.引用

3.1引用的概念

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

引用的使用形式:类型& 引用的变量名{对象名}=引用实体

eg:

#include<iostream>
using std::cout;
using std::cin;
using std::endl;
int main()
{
	int a = 1;
	int& b = a;
	int& c = b;
	int& d = c;
	
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
	cout << d << endl;
	return 0;
}

代码运行的结果为:
在这里插入图片描述

3.2引用的特性

1.引用在定义时必须初始化

#include<iostream>
using namespace std;
int main()
{
	int a = 10;
	int& ra;//编译会报错
	return 0;
}

编译运行的结果为:
在这里插入图片描述
正确的eg:

#include<iostream>
using namespace std;
int main()
{
	int a = 10;
	int& ra = a;
	return 0;
}

2.一个变量可以有多个引用

#include<iostream>
using namespace std;
int main()
{
	int a = 10;
	int& b = a;
	int& c = a;
	int& d = a;

	cout << b << endl;
	cout << c << endl;
	cout << d << endl;

	return 0;
}

代码运行的结果为:
在这里插入图片描述
3.引用一旦引用一个实体,再不能引用其他实体

#include<iostream>
using namespace std;
int main()
{
	int a = 10;
	int x = 5;
	int& b = a;
	int& b = x;
	
	return 0;
}

代码运行的结果为:
在这里插入图片描述

3.3使用场景

注意:引用的类型必须和实体是同种类型

eg1:

//交换变量
#include<iostream>
using namespace std;
void Swap1(int& a, int& b)
{
	int tmp = a;
	a = b;
	b = tmp;
}
int main()
{
	int a = 1;
	int b = 2;
	cout << "交换之前:>" << endl;
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	Swap1(a, b);
	cout << "交换之后:>" << endl;
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	return 0;
}

代码运行的结果为:
在这里插入图片描述
代码运行的结果为:
eg2:

//交换地址
#include<iostream>
using namespace std;
void Swap2(int*& p1, int*& p2)
{
	int* tmp = p1;
	p1 = p2;
	p2 = tmp;
}
int main()
{
	int a = 10;
	int b = 20;
	int* p1 = &a;
	int* p2 = &b;
	cout << "交换地址之前:>" << endl;
	cout << "p1 = " << p1<< endl;
	cout << "p2 = " << p2 << endl;
	//Swap2(&a, &b);
	Swap2(p1, p2);
	cout << "交换地址之后:>" << endl;
	cout << "p1 = " << p1 << endl;
	cout << "p2 = " << p2 << endl;
	return 0;
}

代码运行的结果为:
在这里插入图片描述

总结: 引用做参数的优点:①输出型参数,可以通过形参改变实参,减少编译器压栈的操作,提高了效率;②引用做参数还适用于大对象/深拷贝对象。

2.引用做返回值
eg1:

//引用做返回值--全局变量
#include<iostream>
using namespace std;
int& Count()
{
	static int n = 0;
	n++;
	return n;
}
int main()
{
	int ret = Count();
	cout << ret << endl;
	return 0;
}

正常传参返回:不是直接返回,在前面我们学习过的函数栈帧的知识,在销毁栈帧之前,把返回的值存放到一个临时变量(可能是寄存器)中,然后再把临时变量的值拷贝到main函数的ret中。

代码运行的结果为:
在这里插入图片描述
eg2:

//引用做返回值--局部变量
#include<iostream>
using std::cout;
using std::cin;
using std::endl;
int& Count(int x)
{
	int n = x;
	n++;
	return n;
}
int main()
{
	int ret = Count(1);//ret的值是函数栈帧销毁后,变量n里面存放的值,可能会被清理
	//修改ret不会访问到n的内存空间
	cout << ret << endl;
	return 0;
}

代码运行的结果为:
在这里插入图片描述

当在返回值中使用引用的时候,返回局部变量的引用是否存在问题呢?这里打印的ret的值是不确定的,如果Count函数结束,没有清理栈帧,那么ret的结果侥幸正确,如果Count函数结束,清理栈帧,那么ret的结果是随机值。

eg3:

#include<iostream>
using std::cout;
using std::cin;
using std::endl;
int& Count(int x)
{
	int n = x;
	n++;
	return n;
}
int main()
{
	int& ret = Count(1);//ret是变量n的别名,指向变量n的空间,修改ret会造成非法访问
	cout << ret << endl;
	//使用其他函数,函数栈帧会被清理
	printf("aaaaaaaaaa\n");
	rand();
	cout << ret << endl;
	return 0;
}

代码运行的结果为:
在这里插入图片描述
eg4:

//引用做返回值,具有修改返回值和获取返回值的功能
#include<iostream>
#include<assert.h>
using std::cout;
using std::cin;
using std::endl;
int& WRarry(int* a, int pos)
{
	assert(a);
	return a[pos];
}
int main()
{
	int a[10] = { 0,1,2,3,4,5,6,7,8,9 };
	WRarry(a, 0) = 1;
	cout << WRarry(a, 0) << endl;
	WRarry(a, 0) += 5;
	cout << WRarry(a, 0) << endl;
	return 0;
}

代码运行的结果为:
在这里插入图片描述

总结: 1.基本任何场景都可以引用传参;2.谨慎用引用返回值,出了函数作用域,对象不在了,不能用引用返回,出了函数作用域;对象还在,可以用引用返回3.使用静态变量、动态内存开辟空间的变量;4.引用做返回值,具有修改返回值和获取返回值的功能。

3.4常引用

eg1:

#include<iostream>
using std::cout;
using std::sin;
using std::endl;
void TestConstRef()
{
	//引用过程中,权限可以平移或者缩小
	int x = 0;
	int& y = x;
	const int& z = y;
	x++;
	cout << x << endl;
}

int类型的yint类型的x取别名,相当于权限平移,对const int 类型的z对int类型的y取别名,变量z不能被修改,权限缩小,但不会影响变量x\y的性质。

eg2:

void TestConstRef()
{
	//int& a = 10;
	const int& a = 10;
}

如果直接对常量取别名,此时别名是一个变量,相当于常量的权限扩大了,不能直接对常量进行引用,需要加上const修饰–常引用

eg3:

void TestConstRef()
{
	const int a = 10;
	//int& b = a;
	int& b = 10;
}

在上面代码中,aconst int修饰成为了一个常量,如果使用int&a取别名bb的类型为int类型,b可以被修改相当于权限扩大了。

eg4:

void TestConstRef()
{
	int a = 1;
	double d = 1.1;
	int& c = d;
}

在上面的代码中,发生了强制类型转换。以上面的代码为例,double类型的d在转换int类型的时候,会转换后的变量d存放到一个临时变量中去,再由临时变量拷贝到变量a中去,而该临时变量具有常性(即常量的性质,相当于有const修饰),不直接进行引用,而是进行常引用。

eg5:

#include<iostream>
using std::cout;
using std::sin;
using std::endl;
void TestConstRef()
{
	//引用过程中,权限可以平移或者缩小
	int x = 0;
	int& y = x;
	const int& z = y;
	x++;
	cout << x << endl;
}

int TestConstRef()
{
	static int x = 0;
	return x;
}
int main()
{
	int& ret=TestConstRef();
	return 0;
}

代码运行的结果为:
在这里插入图片描述

在函数中不管使用局部变量还是全局变量,在返回值之前会先把值存放到临时变量中,再由临时变量拷贝到变量ret中去,该临时变量具有常性(相当于有const修饰),不能直接进行引用,而是进行常引用

总结: 引用过程中,权限可以缩小或平移,但权限不能放大,对常量或具有常量性质的变量(实质也是常量),需要进行常引用(有const修饰),对变量进行常引用相当于权限缩小。

3.5引用和指针的区别

eg:

#include<iostream>
using std::cout;
using std::cin;
using std::endl;
int main()
{
	int a = 10;
	//语法层面:不开空间,是对a取别名
	int& ra = a;
	ra = 20;
	//语法层面:开空间存储,存储a的地址
	int* pa = &a;
	*pa = 30;
	return 0;
}

转化为汇编代码的结果为:
在这里插入图片描述

从汇编代码实现的角度看,引用类似指针的实现方式;但是C++在语法层面上默认引用是不开空间的,而指针需要开辟空间存储地址。

4.总结

本章我们一起学习了C++缺省、函数重载、引用的相关知识,希望对大家学习C++有些许帮助!感谢大家阅读,如有不对,欢迎纠正!⭐⭐⭐

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/555487.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Flutter2.x升级3.x版本遇到的问题及解决方案

项目原本使用的Flutter版本为2.5.3&#xff0c;现在要升级到3.0.5版本&#xff0c;结果升级完后项目直接编译不通过&#xff0c;报了一堆的错误&#xff0c;如果你也是这种情况&#xff0c;可以按我接下来讲的操作试一试&#xff0c;反正我就是这么解决问题的。 目录 1、升级G…

连锁管理系统有哪些功能?如何选择实用的连锁管理系统?

传统门店管理系统有很多弊端&#xff0c;各种销售数据不能实时同步、沟通效率低、分店管理困难&#xff0c;库存混乱...... 一套合适的连锁管理系统&#xff0c;能够有效解决多门店之间的管理沟通难题&#xff0c;总店可以随时随地使用手机掌控分店各种事项&#xff0c;多门店之…

云原生之深入解析Airbnb的动态Kubernetes集群扩缩容

一、前言 Airbnb 基础设施的一个重要作用是保证我们的云能够根据需求上升或下降进行自动扩缩容&#xff0c;我们每天的流量波动都非常大&#xff0c;需要依靠动态扩缩容来保证服务的正常运行。为了支持扩缩容&#xff0c;Airbnb 使用了 Kubernetes 编排系统&#xff0c;并且使…

三分钟上线你自己的Midjourney

文章尾部有demo 江湖惯例&#xff1a;先来一波感谢&#xff0c;感谢laf&#xff0c;让我们可以不使用魔法、免费接入Midjourney&#xff0c;不了解laf的请猛戳 Laf介绍 背景 laf官方最近发布了一个活动&#xff0c;活动链接&#xff0c;新手也可以接入哦&#xff01;废话不多…

优维低代码实践:页面编排优化与数据联调

优维低代码技术专栏&#xff0c;是一个全新的、技术为主的专栏&#xff0c;由优维技术委员会成员执笔&#xff0c;基于优维7年低代码技术研发及运维成果&#xff0c;主要介绍低代码相关的技术原理及架构逻辑&#xff0c;目的是给广大运维人提供一个技术交流与学习的平台。 优维…

NEEPU Sec 2023公开赛Reverse题目复现

文章目录 一.Base二.How to use python1.程序逻辑分析2.爆破flag[11]~flag[14]3.爆破sha14.sha256掩码爆破 三.IKUN检查器1.查看程序信息2.分析程序逻辑3.button1_conClick函数4.check1函数5.check2函数6.check3函数7.check4函数8.check5函数 四.junk code1.使用32位动态调试工…

[Nginx 发布项目] 打包后的项目,使用nginx发布

前提 &#xff1a;使用的 mars3d 沐瑶大佬 修改后的nginx , - 下载地址 使用的是 Mars3D三维可视化平台 | 火星科技 修改后的 nginx 发布的服务&#xff0c;确保nginx发布服务时正常 &#xff1b; 如果不是&#xff0c;那这里应该没有你想要的答案&#xff1b; 1、直接替换…

006 - RCC时钟树(一)时钟树内容

006 - RCC时钟树&#xff08;一&#xff09;时钟树内容 本节内容一定要结合RCC时钟树和官方手册学习&#xff0c;如果看不明白的话&#xff0c;建议看一下野火官方的教程&#xff0c;火哥讲这节讲的很详细&#xff0c;看一遍基本就能理解了。 上节内容中分析了启动代码&#…

Web缓存服务——Squid代理服务器应用

正向代理&#xff1a;代替客户端向服务端发送请求。 反向代理&#xff1a;代理服务端&#xff0c;将请求转发给多个服务端。 一、Squid代理服务器介绍 Squid 主要提供缓存加速、应用层过滤控制的功能。 1.1 代理的工作机制&#xff08;缓存网页对象&#xff0c;减少重复请求…

2023年,Facebook Messenger群发这样做

使用SaleSmartly的企业都知道&#xff0c;SaleSmartly&#xff08;ss客服&#xff09;能在 Facebook Messenger群发信息&#xff01;Facebook Messenger在全球最受欢迎通信软件中排名第三&#xff0c;紧追头两位的 WhatsApp和微信。善用 Facebook Messenger群发工具&#xff0c…

华为OD机试真题 Java 实现【区块链文件转储系统】【2023Q2 200分】

一、题目描述 区块链底层存储是一个链式文件系统&#xff0c;由顺序的N个文件组成&#xff0c;每个文件的大小不一&#xff0c;依次为F1,F2…Fn。 随着时间的推移&#xff0c;所占存储会越来越大。 云平台考虑将区块链按文件转储到廉价的SATA盘&#xff0c;只有连续的区块链…

为什么都在学python?

自然是因为Python简单易学且应用领域广&#xff01; Python近段时间一直涨势迅猛&#xff0c;在各大编程排行榜中崭露头角&#xff0c;得益于它多功能性和简单易上手的特性&#xff0c;让它可以在很多不同的工作中发挥重大作用。 正因如此&#xff0c;目前几乎所有大中型互联…

毕业三年月薪才21K,真是没出息......

“害&#xff0c;毕业三年月薪才拿21k,真失败&#xff0c;真的给同龄人拖后腿&#xff01;”这是人能讲出来的话&#xff1f;这就是凡尔赛天花板&#xff1f;这就是我公司的测试部门的人说出来的话&#xff0c;他计算机专业毕业三年&#xff0c;包括实习&#xff0c;在我们公司…

LeetCode:28. 找出字符串中第一个匹配项的下标

28. 找出字符串中第一个匹配项的下标 1&#xff09;题目2&#xff09;代码1.方法一&#xff1a;每个字符进行匹配2.方法二&#xff1a;截取字符串进行匹配 3&#xff09;结果1.方法一结果2.方法二结果 1&#xff09;题目 给你两个字符串 haystack 和 needle &#xff0c;请你在…

Dropwizard 开发环境搭建

Dropwizard是一个Java框架&#xff0c;其目标是提供高性能、高可靠的Web 应用程序的实现。 一、使用Maven原型创建项目 1、新建项目->选择Maven Archetype 填写好项目名称、路径、选择JDK版本&#xff0c;这里使用JDK11及以上的版本&#xff0c;如下图所示&#xff1a; 2…

自监督对比学习系列论文(一):无引导对比学习--MOCO,SimCLR

自监督对比学习 对比学习&#xff08;self-supervised learning&#xff09;的应用场景是用无标记或者少标记的数据进行模型的预训练以得到一个较好的预训练模型&#xff0c;然后便可将该模型轻松的迁移到到下游任务上。显而易见的&#xff0c;对比学习的难点在于我们如何在没有…

【论文下饭】PatchTST中的channel-independence

PatchTST中的channel-independence 总结PatchingChannel-independence A Time Series is Worth 64 Words: Long-term Forecasting with Transformers 时间&#xff1a;2022 引用&#xff1a;8 ICLR 2023 代码&#xff1a;https://github.com/yuqinie98/PatchTST 中文参考&#…

软件开发人技能变现方案来啦~

java单体服务Uniapp客户端 欢迎大家来关注java单体服务Uniapp客户端模式开发应用程序这个模式下产品的特点互联网大厂产品特点小服务小产品-存在价值普通人慢慢挣小钱 欢迎大家来关注 你好&#xff01; 这可能是你第一次来“莹未来”这里&#xff0c;郑重欢迎您。如果你想学习…

firewalld防火墙详细介绍

目录 一、firewalld概述 二、firewalld与iptables的区别 1.位置不同 2.配置存储位置不同 3.规则运行不同 4.防火墙类型不同 三、firewalld区域的概念 四、firewalld防火墙9个区域 1、trusted&#xff08;信任区域&#xff09; 2、public&#xff08;公共区域&#xf…

JavaScript中的tab栏切换制作(排他思想)

文章目录 实现效果图排他思想tab栏切换制作思路代码部分 实现效果图 整个页面分为2个部分&#xff0c;tab_list部分&#xff08;上半部分&#xff09;和tab_con部分&#xff08;下半部分&#xff09; tab_list部分包含5个li&#xff0c;它们分别与tab_con部分的5个div盒子一一…