前言
上一篇博客中提到c++在c语言的基础上增加了许多特性,其中提到了函数重载和引用,通过函数重载,可以使用相同的函数名来实现不同的功能,可以根据不同的参数类型和个数进行函数的重载,从而提高了函数的灵活性;使用引用作为函数参数时,可以避免因参数传递而引起的对象拷贝,提高了程序的执行效率。接下来让我们深入了解一下函数重载及引用!
一、函数重载是什么? 引用是什么?
1. 函数重载的定义
函数重载是指在同一个作用域内,可以定义多个函数名相同但参数列表不同的函数。在调用这个函数时,编译器会根据传入的参数类型和数量来确定应该调用哪个函数。
实际就是函数名可以重复 但是参数类型不同,或参数类型相同而参数的个数不同
#include<iostream>
using namespace std;
int Add(int x, int y)
{
return x + y;
}
double Add(double x, double y)
{
return x + y;
}
float Add(int x, float y)
{
return x + y;
}
int main()
{
cout << Add(3,2) << endl;
cout << Add(5.5, 6.5) << endl;
cout << Add(2, 5.5) << endl;
return 0;
}
函数重载的规则:
①函数名必须相同
②参数列表必须不同(个数不同、类型不同、参数排序顺序不同)
③只有函数的返回值不同(即函数名,参数类型及个数均相同)不构成重载
2.引用的定义
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空 间,它和它引用的变量共用同一块内存空间
实际就是就是给你起了个小名,人还是同一个人(内存空间还是那一块)
void test()
{
int a = 10;
int& ra = a;
int& rra = a;
printf("%p\n", &a);
printf("%p\n", &ra);
printf("%P\n", &rra);
}
引用的规则
①引用在定义时必须初始化
// int &y; ————错误
int x = 0;
int& y = x; //正确
② 一个变量可多个引用
int a = 10;
int& x = a;
int& y = a;
int& z = a;
③引用一旦引用了一个实体,便不能引用其它实体
int a = 10;
int e = 1;
int& b = a;
b = e; //该语句为赋值语句
e = 2;
printf("%d",b); //b的值不改变
二、深入函数重载
调用函数时,编译器会根据函数调用的实参类型和个数来选择相应的函数进行调用。如果没有找到完全匹配的函数,则编译器会尝试进行隐式类型转换或者参数个数的匹配来寻找最合适的函数进行调用。如果仍然无法找到匹配的函数,则会出现编译错误。
C++ 中的函数重载是通过名称修饰(Name Mangling)来实现的。
从该图可以看出两个同名函数被起了不同名字 一个是<_Z1fid> 另一个是<_Z1fdi> 眼尖的小伙伴立马可以看出最后两位字母不就是对应函数参数类型的首字母,让我们深入解析一下其它字母分别代表什么!
函数名修饰规则
C++的函数名修饰规则有些复杂,但是通过分析修饰名不仅可以知道函数的调用方式。返回值类型,參数个数甚至參数类型。命名规则: _Z+函数名长度+函数名+类型首字符
需要注意的是,不同的编译器可能会生成不同的函数名称,因此在链接不同编译器生成的目标文件时可能会出现问题,例如链接器无法找到或匹配对应的函数名,从而导致链接错误,也有可能出现符号重复定义或未引用定义。因此尽量在同一编译器及其版本下编译所有相关代码,以确保生成的目标文件使用相同的函数名称规则。
三、深入引用
在C++中,指针和引用虽然可以实现类似的功能,但它们的底层逻辑是有一些区别的。
-
指针是一个变量,存储的是另一个变量的内存地址,通过指针可以间接访问这个变量。指针可以被重新赋值指向不同的内存地址,也可以被设置为nullptr表示空指针。指针需要通过解引用操作符(*)来访问所指向的变量。
-
引用是一个变量的别名,引用在创建时必须初始化,并且不能再改变引用的目标。引用本质上是对变量的一种别名,当操作引用时,实际上操作的是引用所绑定的变量。引用在使用上更加简洁直观,不需要像指针那样使用解引用操作符。
在底层实现上,指针和引用有一些区别。指针在内存中存储的是变量的地址,而引用在编译时就会被替换为对应变量的地址,因此在底层上可以说引用是通过指针来实现的,但在语法和使用上有很大的不同。
引用做返回值和做参数
在 C++ 中,可以使用引用作为函数的返回值。这样做通常可以避免不必要的拷贝操作,提高程序的运行效率。
#include <iostream>
int& returnReference(int& x) {
x = x * 2;
return x;
}
int main() {
int value = 5;
int& ref = returnReference(value);
std::cout << "Value after function call: " << value << std::endl; // 输出结果为 10
std::cout << "Reference value: " << ref << std::endl; // 输出结果为 10
return 0;
}
在上面的示例中,returnReference
函数接受一个整数引用作为参数,并对其进行操作后返回同一个引用。在 main
函数中,我们调用 returnReference
函数,并将返回的引用存储在 ref
变量中,从而可以访问并修改原始值。需要注意的是,使用引用作为返回值时要确保返回的引用指向的对象在函数调用结束后仍然有效。