c++编程(1)——重载函数、引用

欢迎来到博主的专栏——c++编程
博主ID: 代码小豪

文章目录

    • 前言
    • 重载函数
    • 函数重载的规则
    • 函数重载的原理
    • 引用
    • 引用变量的权限问题

前言

c语言对于编写大型项目有所缺陷,比如最常出现的标识符不能重复的问题(软件的代码量通常是数以万计的,而且由多人编写,因此命名的变量、函数重名是一个非常常见的问题)。因此当时就有人对c的功能进行扩展,增加了类的功能。再经过了多年的继续扩展,就发展处了c++这个编程语言。

由于c++是由c扩展而来的,因此c/c++之间互通的特性非常之多。想要学习c++,是不能绕开c语言的特性的。但是由于博客的篇幅原因,且博主在之前的专栏也有对c语言语法进行过讲解。所以在这个专栏中出现的C语言语法不会进行讲解。本专栏重点讲解一些c++有、而C语言没有的特性。以及一些c++与c语言有所差异的特性。

重载函数

前面提到了c语言存在的缺陷之一就是标识符不能重复,为了解决这个问题,c++提供了重载函数这个特性。

大家在平时的生活中有没有见过那种,词一样但是意思完全不同的句式。比如:“豆腐一块两块”,这句话有多种解读方式,具体是什么意思,还是要根据实际情况来解读。

重载函数也是同理,相同的函数名,如果函数类型不同,执行的方式也不同。如果是c语言则不允许这种形式,但是在实际运用当中是可能发生的。

比如:

int add(int a, int b)
{
	return a + b;
}

double add(double a, double b)
{
	return a + b;
}

前者的add函数用来计算整型数据相加、后者计算浮点类型数据相加。这在数学当中是不是允许的情况?但是c语言并不允许出现同名函数。因此很多人的解决方式都是加上前缀。

int int_add(int a, int b)
{
	return a + b;
}

double double_add(double a, double b)
{
	return a + b;
}

c++的重载函数的特性则可以忽略这个细节,重载函数可以让拥有相同函数名、但是不同参数的函数共存。而且会根据实际上传的参数来决定调用哪个函数。

int main()
{
	int x, y;
	x = 10, y = 20;
	double a, b;
	a = 3.1415, b = 1.4444;

	printf("x+y=%d\n", add(x, y));
	printf("a+b=%lf\n", add(a, b));
	return 0;
}

x、y都是整型元素,因此调用的add为整型相加的add。a,b是浮点型数据,因此调用的add是浮点型相加的add。

结果如下:
在这里插入图片描述

函数重载的规则

重载函数的规则如下:

(1)函数的参数类型不同
(2)函数的参数数量不同
(3)函数的参数顺序不同

相同函数名的函数符合以上一条条件即可构成重载函数。

比如:

int add(int a, int b)//(1)
{
	return a + b;
}

double add(double a, double b)//(2)
{
	return a + b;
}

double add(int a, double b)//(3)
{
	return a + b;
}

double add(double a, int b)//(4)
{
	return a + b;
}

int add(int a, int b, int c)//(5)
{
	return a + b + c;
}

(1)与(2)的重载符和第一个条件,(3)和(4)的重载符合第二个条件。(5)则符合第三个条件

函数重载的原理

为什么c++可以支持函数重载,而C语言不行呢?这得从函数调用的角度解释。

函数调用大家都清楚,但是函数调用是具体如何调用的呢?这次我们尝试从汇编角度来理解。
在这里插入图片描述

注意红色部分的call就是调用。call后面紧接的是函数名,将两者结合起来就是调用add函数这个操作。而函数名后面的16进制数是什么呢?没错就是函数的地址。

这时可能有人就有疑问了,我知道变量有地址,指针有地址,函数也有地址吗?是的,函数名就是函数的地址。在c语言中就有函数指针这个指向函数的指针。而函数名代表的就是函数的地址。

	int(*pf)(int, int) = add;//这个pf就是函数指针,
	//add则是函数的地址值,pf是指向add函数地址的函数指针

我们在汇编语言中可以看到,这五个重载函数的函数名代表的地址都是不同的。

因此我们可以来猜想一下:c++之所以可以支持重载函数,是因为c++可以为相同函数名,不同函数参数的函数设置不同的地址,而c语言则不会分辨相同函数名的函数是否具有相同的参数

那么c++为什么可以做到根据不同的函数参数进行不同的地址分配,而C语言不可以。难道说c++内置了一个人工智能?

这显然是不可能的。c++采用了另外一种命名方式:

由编译器设置一个符号表,根据函数的返回类型、参数类型、函数名。翻译成一个新的函数名。

在这里插入图片描述
相信使用过c++的人对这个报错应该很熟悉。但这里不讲报错的原因,而是注意报错中的重要信息

在这里插入图片描述
可以发现这五个乱码非常相似,而且这些乱码对应的函数也是我们的老熟人(add五兄弟)。在仔细观察乱码,我们可以发现一个规律。
在这里插入图片描述
除了这几个符号以外,其余乱码都是一致的,根据这五个函数的函数原型,我们可以大胆做一个猜测:在vs中(不同编译器的符号表不同),H对应参数类型int,N对应参数类型double

这些乱码就是编译器根据符号表将函数翻译过后的函数名。也就是说c++中,经过编译后的函数名不再是add,而是根据翻译过后乱码才是这个函数真正的函数名,函数名不同,调用的函数地址也不同,这是c++实现函数重载的原理。

引用

我写了一个函数,用来交换两个变量的值。请大家来判断以下这个函数有什么问题?

void Swap(int a, int b)
{
	int tmp = a;
	a = b;
	b = tmp;
}

不知道大家再刚入门C语言的时候有没有出现过这种错误,将函数的形式参数认为是实际参数。有了经验以后才明白,形式参数是实际参数的临时拷贝,对形式参数的修改不会影响到实际的参数。为了解决这个问题,可以将函数参数修改成指针类型。

void Swap(int* pa, int* pb)
{
	int tmp = *pa;
	*pa = *pb;
	*pb = tmp;
}

这是利用指针的特性来实现对实际参数修改的功能,但是在面对多级指针的情况下,很容易忽略掉实参与形参的关系。

c++支持的引用类型可以避免这个问题。引用的操作符是(&),在C语言中这个操作符是取地址操作符,在c++这个符号依然可以作为取地址操作符,但是它还有新增的一个作用:

将&用于变量的声明时,可以将这个变量的类型改为引用类型

好比C语言中的解引用操作符(*),当这个符号用于两个变量或常量之间时,是相乘操作符。(&)在c++中也具备了两用的功能。

引用符号只能使用在变量的类型声明之后。比如:

	int a = 0;
	int& b = a;

此时变量b就是a的引用。对b进行的任何赋值操作都会对a进行修改。

	b = 20;
	b++;

此时a会先赋值20,在自加1,因此a的值被修改为21。

对一个变量,可以有多个引用,对其中任意一个引用变量进行操作都会对其余变量造成影响

int main()
{
	int a = 0;
	int& b = a;
	int& c = a;

	c++;
	b++;
	printf("a=%d\n", a);
	printf("b=%d\n", b);
	printf("c=%d\n", c);
	return 0;
}

b、c同为a的引用变量,对c进行自加操作、a,b,c都会自加1,b也是同理,因此输出结果a,b,c都是2.

引用变量也可以用来引用引用变量,这句话有点绕,但是看代码就能一下子理解。

	int a = 0;
	int& b = a;
	int& c = a;
	int& d = b;

此时d就成了b的引用变量,对a,b,c,d的任何操作,都会对其余变量产生影响。

这种操作在C语言也可以用指针来实现。比如:

int a = 0;
	int* b = &a;
	int* c = &a;
	int* d = b;

	(*c)++;
	(*b)++;
	(*d)++;

难道引用就是C语言指针的变种吗?当然不是,引用和指针的功能类似,但是原理不一样。C语言是用指针指向变量的地址空间,通过解引用来操控变量。而c++的引用更像是为同一个地址空间同时赋予了多个变量名而已。

在这里插入图片描述

	int a = 0;
	int& b = a;

    rintf("%p\n", &a);
	printf("%p\n", &b);

运行这段代码也可以发现,a与b取地址后显示的地址空间是一致的。

引用类型变量也可以用来引用指针,只是位置要在(*)之后

    int* pa = &a;
	int*& pb = pa;
	int&* pc = pb;//error 不允许指向引用的指针

引用变量也可以用来作为函数的参数,此时对形参的修改就会影响到实参。

void Swap(int&a, int& b)
{
	int tmp = a;
	a = b;
	b = tmp;
}

引用变量的权限问题

引用需要遵守以下规则

(1)声明引用变量时必须赋值,且后续不能修改
(2)声明的引用变量不能扩大原变量的权限。

第一个很好理解,因为引用变量可以视为原变量的副本,既然是副本那就一定要有原本才能复制。

第二个条件就有点复杂了,什么是放大原变量权限,如果缩小原变量的权限又可不可行呢?

我们先回到c语言

int main()
{
	const int a = 0;
	int* pa = &a;
	(*pa) = 10;
	return 0;
}

在C语言中会出现这种情况:变量a明明是被限定成const类型的了,按理来说,这个a是绝对不能修改的,但是通过指针,我们可以绕过这个const,将a进行修改,这是不是违背了当初变量a被设计出来的初心了。因此C++新增了这个特性。原变量的权限不能被放大。

比如:

	const int a = 0;
	int& b = a;//error 
	const int& b = a;//true

c++想要绕开这个权限被禁用了。如果想要通过引用const类型的变量来修改值,会出现这种报错:
在这里插入图片描述
a本来是被限定了的,而b并没有被限定,这就是权限的放大,而const int类型与a的权限是平行的,因此不会报错。

如果是将权限进行缩小呢?

	int a = 0; 
	const int& b = a;//true
    int& c = a;//true

答案是允许的。那么b的权限被缩小了,会不会对a和c有所影响呢?

	int a = 0; 
	const int& b = a;//true
    int& c = a;//true

	a++;//true
	b++;//error
	c++//true;

可以发现被限制权限的b不能进行修改操作,而a和c可以,所以对a和c的操作仍然能影响b,但是这不违背原变量的设计初衷,毕竟创建a的时候并没有限定a的操作权限。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器语言编写helloworld

kvmtool下载编译 git clone https://github.com/kvmtool/kvmtool.git 下载后进入到目录执行make即可。 补码 计算机怎么表示负数?以四位有符号数为例,使用高位作为符号位,最高位为0表示正数,为1表示负数,其余三位用…

基于SSM远程同步课堂系统

基于SSM远程同步课堂系统的设计与实现 摘要 在这样一个网络数据大爆炸的时代,人们获取知识、获取信息的通道非常的多元化,通过网络来实现数据信息的获取成为了现在非常常见的一种方式,而通过网络进行教学,在网络上进行远程的课堂…

【软考】数据流图的设计原则

目录 1. 数据守恒原则2. 守恒加工原则3. 外部实体与外部实体之间不存在数据流4. 外部实体与外部存储之间不存在数据流5. 数据存储与数据存储之间不存在数据流6. 父图与子图的平衡原则7. 数据流与加工有关,且必须经过加工8.例题8.1 例题1 1. 数据守恒原则 1.输入与输…

嵌入式linux学习之opencv交叉编译

1.下载opencv源码 OpenCV官方源码下载链接为https://opencv.org/releases/,选择3.4.16版本下载。放在ubuntu系统~/opencv文件夹中,解压缩,opencv文件夹中新建build和install文件夹用于存放编译文件和安装文件: 2. 安装编译工具…

ES的RestClient相关操作

ES的RestClient相关操作 Elasticsearch使用Java操作。 本文仅介绍CURD索引库和文档!!! Elasticsearch基础:https://blog.csdn.net/weixin_46533577/article/details/137207222 Elasticsearch Clients官网:https://ww…

MD5 计算 (下一代加密辅助类, Win32, C++)

CCNGHelper.h #pragma once #include <string> #include <tchar.h> #include <windows.h> #include <bcrypt.h>#ifdef _UNICODE using _tstring std::wstring; #else using _tstring std::string; #endif// 下一代加密辅助类 // 客户端: Windows Vi…

Vue2(十二):Vuex环境搭建、Vuex工作原理、Vuex开发者工具、几个配置项、多组件共享数据、Vuex模块化

一、Vuex 1.概念 专门在Vue中实现集中式状态&#xff08;数据&#xff09;管理的一个Vue插件&#xff08;use引入&#xff09;&#xff0c;对vue应用中多个组件的共享状态进行集中式的管理&#xff08;读&#xff0f;写&#xff09;&#xff0c;也是一种组件间通信的方式&…

阿里云优惠券领取方法大公开,省钱不再是难事

阿里云作为国内领先的云计算服务提供商&#xff0c;为广大用户提供了丰富的云产品和解决方案。为了吸引用户上云&#xff0c;阿里云经常推出各种优惠活动&#xff0c;其中最受用户欢迎的就是阿里云优惠券。那么&#xff0c;阿里云优惠券究竟是什么呢&#xff1f;我们又该如何领…

代码随想录第25天|216.组合总和III 17.电话号码的字母组合

216.组合总和III 216. 组合总和 III - 力扣&#xff08;LeetCode&#xff09; 代码随想录 (programmercarl.com) 和组合问题有啥区别&#xff1f;回溯算法如何剪枝&#xff1f;| LeetCode&#xff1a;216.组合总和III_哔哩哔哩_bilibili 找出所有相加之和为 n 的 k 个数的组…

基于自动编码器的预训练模型方法模型预训练方法RetroMAE和RetroMAE-2

文章目录 RetroMAERetroMAE详情编码解码增强解码 RetroMAE-2RetroMAE-2详情编码[CLS]解码OT解码和训练目标向量表征 总结参考资料 RetroMAE RetroMAE 出自论文《RetroMAE: Pre-Training Retrieval-oriented Language Models Via Masked Auto-Encoder》&#xff0c;是一种针对于…

「MySQL」索引事务

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;数据库 &#x1f387;欢迎点赞收藏加关注哦&#xff01; 索引&事务 &#x1f349;索引&#x1f34c;特点&#x1f34c;通过 SQL 操作索引&#x1f34c;底层数据结构 &#x1f349;事务&…

网络编程的学习1

网络编程 在网络通信协议下&#xff0c;不同计算机上运行的程序&#xff0c;进行数据传输。 三要素 ip&#xff1a;设备在网络中的地址&#xff0c;是唯一的标识。 ipv4:采取32位地址长度&#xff0c;分成4组。 ipv6&#xff1a;采用128位地址长度&#xff0c;分成8组。 …

安卓SharedPreferences使用

目录 一、简介二、使用2.1 getSharedPreferences2.2 增加数据2.3 读取数据2.4 删除数据2.5 修改数据2.6 清除数据2.7 提交数据 一、简介 SharedPreferences是Android平台上一个轻量级的存储类&#xff0c;主要是保存一些常用的配置比如窗口状态&#xff0c;一般在Activity、重…

12.Python文件读写

文件是数据的载体&#xff0c;程序可以从文件中读取数据&#xff0c;也可以将数据写 入文件中&#xff0c;本章重点介绍如何在Python中进行文件读写。 1 打开文件 我们在使用文件之前要先将文件打开&#xff0c;这通过open&#xff08;&#xff09;函数实现。 open&#xff0…

JJJ:linux系统中第一个进程

以linux4.19内核linux系统中第一个进程。 执行shell指令 ps -ef 结果如下&#xff1a; xxxxxx-virtual-machine:~$ ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 20:55 ? 00:00:02 /sbin/init splash root …

【Web应用技术基础】CSS(4)——背景样式

第1题&#xff1a;背景颜色 .html <!DOCTYPE html> <html><head><meta charset"utf-8"><title>Hello World</title><link rel"stylesheet" href"step1/CSS/style.css"> </head><body>&…

词令蚂蚁庄园今日答案正确答案怎么获取查看蚂蚁庄园今天问题的正确答案?

词令蚂蚁庄园今日答案正确答案怎么获取查看蚂蚁庄园今天问题的正确答案&#xff1f; 1、打开「词令」关键词口令直达工具&#xff1b; 2、输入词令关键词直达口令「今日答案999」&#xff1b; 3、搜索直达词令蚂蚁庄园今日问题的正确答案&#xff1b; *注&#xff1a;词令蚂蚁…

【PythonGIS】Python实现批量导出面矢量要素(单个多面矢量->多个单面矢量)

可怜的我周六还在工作&#xff0c;已经很久没更新过博客了&#xff0c;今天正好有空就和大家分享一下。今天给大家带来的是使用Python将包含多个面要素/线要素的矢量批量导出单个要素的矢量&#xff0c;即一个要素一个矢量文件。之前写过多个矢量文件合并成一个矢量文件的博文&…

西南交大swjtu算法实验3.3|穷举法

1.实验目的 通过具体例子学习排列这种典型的穷举算法的求解过程以及程序框架&#xff0c;分析其算法的求解过程&#xff0c;以及如何设计穷举法解决实际问题。通过本实验&#xff0c;理解穷举法的特点以及实际应用中的局限性。 2.实验任务 有n (n>1&#xff09;个任务需要…

Visual Studio 2022 中VLD库如何安装

GitHub链接 Release v2.5.1 KindDragon/vld 点击可执行程序进行下载 点击可执行程序进行安装 双击打开 一直点击next即可完成安装&#xff08;不用在意安装路径&#xff0c;总共不到2MB&#xff09; 如果GitHub无法打开&#xff0c;可以私信我发你安装包直接安装