C++基础语法之函数重载、引用

1. 函数重载

1.1 概念

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

//参数的类型不同
int Add(int a, int b)
{
	return a + b;
}
int Add(double a, double b)
{
	return a + b;
}

//参数的个数不同
int Add(int a, int b)
{
	return a + b;
}
int Add(int a, int b, int c)
{
	return a + b + c;
}

//参数的顺序不同
int Add(int a, char b)
{
	return a + b;
}
int Add(char b, int a)
{
	return a + b;
}

注:

  1. 函数的返回参数不同构成不了重载函数
  2. 传参的时候注意类型,发生数据转换的时候可能会出错
int Add(int a, double b)
{
	return a + b;
}

int Add(double a, int b)
{
	return a + b;
}

int main()
{
	Add(20, 20);
	return 0;
}

在这里插入图片描述
注意看这里错误的原因不是参数类型传错了,是编译器判断不了用哪个函数。

1.2 原理

C++支持重载函数的原理是名字修饰(name Mangling),要理解该原理需要知道C语言讲的一个程序运行起来需要步骤。

一个程序需要运行起来需要经过:预处理、编译、汇编、链接。
一个实际的项目中通常包含多个的头文件和源文件,由我们前面的知识知道,当a.cpp调用b.cpp中定义的函数的时候,汇编形成的a.o文件是没有该函数的地址的,该函数在b.o中,所以后面的链接步骤是用来解决该问题的,链接器看到a.o调用函数,但是没有函数的地址,就会到b.o的符号表中找函数的地址,然后链接到一起,那么链接是根据哪个名字去找到该函数的呢?每个编译器都有自己不同的函数名修饰规则。

这里介绍一下Linux中g++编译器的修饰名规则,在采用C语言编译器的时候,对函数名没有修饰,所以C不支持重载函数,而在采用C++语言编译器的时候,函数名修饰之后变成【_Z+函数长度+函数名+类型首字母】
在这里插入图片描述
所以C++可以支持重载,因为参数的不同修饰出来的函数名就不同。

这里在给大家看看Windos下函数修饰名规则
在这里插入图片描述

2. 引用

2.1 概念

引用不是定义一个新的变量,而是给一个已知的变量取一个别名,和那个变量使用同一块空间,编译器不会新分配空间。就好像我们每个人都有外号,无论叫本名还是叫你外号都是叫你这一个人。

语法格式是:变量类型+&+取的别名 = 引用的实体

int main()
{
	int a = 10;
	int& b = a;
	cout << &a << endl << &b << endl;
	return 0;
}

在这里插入图片描述

2.2 特性

  1. 引用在定义时必须初始化
int main()
{
	int& a;
	return 0;
}

在这里插入图片描述

  1. 一个实体可以有很多的引用(就像一个人可以有很多的外号),引用也可以有引用
int main()
{
	int a = 10;
	int& b = a;
	int& c = a;
	int& d = c;
	cout << &a << endl << &b << endl << &c << endl << &d << endl;
	return 0;
}

在这里插入图片描述

  1. 但是一个引用只能有一个实体
int main()
{
	int a = 10;
	int b = 20;
	int& c = a;
	//这里是赋值,不能理解成变成b的引用
	c = b;
	cout << &a << endl << &b << endl << &c << endl;
	return 0;
}

在这里插入图片描述

2.3常引用

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

在这里插入图片描述
这种用法是错误的,因为权限放大了,a被const修饰不能改变,但是b确可以改变,这就冲突了,所以修改的方法就是把b的权限给缩小。

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

注:权限缩小是可以的

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

当我们引用的类型和引用对象类型不同时,编译器报错也是因为这个原因

int main()
{
	double a = 10;
	int& b = a;
	return 0;
}

在这里插入图片描述

可能很多人不理解这跟上面权限有什么关系,这里涉及到两个知识点,(1)在值传递、类型转换使会生成临时变量 (2)临时变量具有常性。

所以我们可以解释上面的代码了,a转换成int型使生成的临时变量,而临时变量具有常性,但是b确没有,所以这里权限放大了,发生了错误,我只需限制b就行。

int main()
{
	double a = 10;
	const int& b = a;
	return 0;
}

2.4 应用场景

  1. 做参数
void Swap(int& a, int& b)
{
	int t = a;
	a = b;
	b = t;
}
int main()
{
	int a = 3;
	int b = 4;
	cout << "a = " << a << endl << "b = " << b << endl;
	Swap(a, b);
	cout << "交换后" << endl;
	cout << "a = " << a << endl << "b = " << b << endl;
	return 0;
}

在这里插入图片描述

  1. 做返回值
int& fun()
{
	static int a = 1;
	a++;
	return a;
}
int main()
{
	cout << fun() << endl;
}

在你使用引用做返回值的时候,你要清楚,在出函数作用域的时候,你引用的对象有没有被系统回收,如果回收了就必须使用值返回了。

/*这种做法就是错误的,在调用完fun函数后变量a会被系统回收,所以a中的值是随机值,
可能有的人运行该段代码得到正确结果,这是因为你所使用的编译器没有清除a中的值*/
int& fun()
{
	int a = 1;
	a++;
	return a;
}
int main()
{
	cout << fun() << endl;
}

2.5 传值、传引用效率比较

以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

struct A {
	int a[10000]; 
};
void TestFunc1(A a){
}
void TestFunc2(A& a) {
}
int main()
{
	A a;
	// 以值作为函数参数
	size_t begin1 = clock();
	for (size_t i = 0; i < 10000; ++i)
		TestFunc1(a);
	size_t end1 = clock();
	// 以引用作为函数参数
	size_t begin2 = clock();
	for (size_t i = 0; i < 10000; ++i)
		TestFunc2(a);
	size_t end2 = clock();
	// 分别计算两个函数运行结束后的时间
	cout << "TestFunc1(A) - time:" << end1 - begin1 <<endl;
	cout << "TestFunc2(A&)-time:" << end2 - begin2 <<endl;

	return 0;
}

在这里插入图片描述

2.6 引用和指针的区别

注:引用在语法上是没有独立空间的,和引用对象使用同一块空间,但是在底层实现上实际是有空间的,是按照指针的方式来实现的。

区别:

  1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
  2. 引用在定义时必须初始化,指针没有要求
  3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何 一个同类型实体
  4. 没有NULL引用,但有NULL指针
  5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32 位平台下占4个字节)
  6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  7. 有多级指针,但是没有多级引用
  8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  9. 引用比指针使用起来相对更安全

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值