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

本文介绍了c++编程中函数重载的概念,包括其规则(如参数类型、数量和顺序不同)、原理以及c++中引用的使用,包括引用变量的声明、操作、权限限制等内容。
摘要由CSDN通过智能技术生成

欢迎来到博主的专栏——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的操作权限。

  • 26
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码小豪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值