C++初阶(二)

一、函数重载

C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题。(如下就是几个实现重载功能的函数)

int Add(int left,int right)
{
	return left+right;
}
double Add(double left, double right)
{
	return left+right;
}
long Add(long left, long right)
{
	return left+right;
}
int main()
{
	Add(10, 20);
	Add(10.0, 20.0);
	Add(10L, 20L);
	return 0;
}

那么问题来了:
为什么C语言不支持函数重载,而C++支持?
首先,他们实现程序的方式都是 预处理 - 编译 - 汇编 - 链接这几个步骤,首先来回顾这几个步骤。

编译四步骤

1.预处理:

头文件展开(比如有#include,展开iostream库,将他所在的文件拷贝到当前文件)/宏替换/去掉注释(文字注释等)/条件编译(ifdef__win32,跨平台问题等)生成 .i文件

2.编译:

检查语法,生成汇编代码(指令级代码,在驱动,嵌入式开发等),生成.s文件

在这里插入图片描述

在此处可以看到汇编代码

3.汇编:

生成指令
在这里插入图片描述

在汇编生成指令后,最后将这些指令交给cpu来执行,但是cpu不认识,所以进行汇编,将汇编代码生成二进制机器码 (01011),这个过程会产生符号表每个全局变量和函数会形成一个符号,这个规程就是将每一个符号
结合生成一个符号表,一个符号是一个标识,此过程还会给符号一个地址,最终将所有符号及其地址组合,形成符号表),最终生成.o文件

4.链接:

将上述三步产生的三个文件进行合并,合并符号表,合并段表,.o文件的结合,形成段表(所谓短表,即每个.c/.cpp文件在经过编译都会生成一个自己的段),生成可执行程序(.out/.exe等)

函数重载真相

而C++能实现函数重载,主要是因为它在编译时与C语言不同

这边首先提到函数名修饰规则

编译器在编译期间创建的一个字符串(也叫符号表名),用来指明函数的定义或原型。用于在汇编时找到这个函数。

C语言编译

无函数名修饰规则,用函数名充当符号表名,直接根据符号表去找,自己区分不开,所以不支持函数重载

C++编译

根据函数名修饰规则,来找地址(vs情况),将类型名带入函数名,用修饰以后的函数名充当符号表名,所以支持重载

如存在如下函数:

int func(int i,double d)
{
	//...
}
int func(double d, int i)
{
	//...
}

我们通过gcc编译器到达编译这一步,会看到两个函数的符号表名:
gcc内,符号表名的编译规则是Z+函数名长度+类型首字母
在这里插入图片描述
根据上述特性,我们也可以得出一个结论:函数返回类型不同,并不会构成函数重载.因为函数返回类型并未在符号表中有体现。

二、引用(&)

所谓引用,就是给已经存在的变量起一个别名。
(正如鲁迅,也叫周树人,哈哈哈哈~)
换句话说,引用=取别名,用法就是类型& 变量名
如:

int a = 10;
int& b = a;

那么这边的a和b都是指向着由a开辟的那块空间

在这里插入图片描述
普通场景下没什么意义,但是在某些场景下,在输出型参数时,就很需要。比如,我们的C语言交换函数。
旧写法:

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

新写法:

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

两种在运行后的结果都是一样的。

*引用满足的条件

那么需要注意的是,引用需要满足以下几个条件:

1.引用初始化时要给值。

int &a;//这是错误写法
int& a = b;//这才是正确的

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

int a = 10;
int& b = a;
int& c = a;

a,b,c指向的是同一块空间所表示的值。

3.引用一旦引用一个实体,再不能引用其他实体

这句换很好理解,引用其他实体,也就意味着重定义,如:

int a = 10;
int b = 20;
int& c = a;
int& c = b;//这里的c引用了其他实体,换个角度就是重定义了,这本身就是不满足语法要求的

4.可以给别名取别名

以下写法是合法的:

int a = 10;
int& b = a;
int& c = b;

注意事项
现有如下代码:

int a = 10;
int& b = a;
int& c = b;
int x = 1;
b = x;

这串代码在运行后,a,b,c的值会被x赋值为1,但是a,b,c是同一个地址,x的地址与三者不同。

它的引用赋值不会改变指向 (Java会改变指向)

*引用做返回值

函数返回值可以是类型,也可以是指针。

如普通函数写法:

int Add(int x, int y);
Node* ListNode(LT* plist);

但是引用同样可以做函数返回值,不过引用做返回值必须满足:如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已经还给系统了,则必须使用传值返回

当函数在引用返回时,这个值必须是全局/堆/静态的对象,才可以使用引用返回。如以下代码就是不合法:

int& Add(int x, int y)
{
	int c = x + y; 
	return c;
}
int main()
{
	int ret = Add(1, 2);
	return 0;
}

在上述代码中,c是一个局部变量,当他以引用的方式被返回时,内存空间已经被清理,那么是否返回理想值主要是看是否被栈空间清理。实际上这一行为是未定义行为,这串代码本身就有问题,这里是一个错误示范

合法写法如下:

int a = 10;
int& Add(int x, int y)
{
	a = x + y;
	return a;
}
int main()
{
	int x = 20;
	int y = 20;
	int ret = Add(x, y);
	cout << ret << endl;
	return 0;
}

上述引用做返回值写法是合法写法,返回值是局部变量,不会有错误。

当返回值在静态区,栈,全局变量时,就可以用引用做返回值这样的写法去写

欢迎一起交流~~

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

温有情

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

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

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

打赏作者

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

抵扣说明:

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

余额充值