【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;
}
  • 返回值不同不是函数重载
short Add(short left, short right)
{
 return left+right;
}
int Add(short left, short right)
{
 return left+right;
}

C语言不能函数重载

编译器内部完成了翻译部分:
1.预处理
1)头文件展开
2)宏的替换
3)去注释
4)条件编译
2.编译过程:将高级语言转为汇编语言
3.汇编过程:汇编语言转为二进制程序
4.链接部分:所引用的数据链接进来

比如一个函数的声明如下:
void function(int x,int y);

在c语言中,编译器在编译后在库中的名字为_function
在c++中,编译器在编译后在库中的名字为_function_int_int

还有一个函数的声明如下:
void function(float x,float y);

在c语言中,编译器在编译后在库中的名字为_function
在c++中,编译器在编译后在库中的名字为_function_float_float
在链接时,都是找名字进行链接的,就比如以上两个函数,
在C语言中两个的名字一样,就会在链接中报错。
C++中它们的名字不一样,所以就不会报错。

通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载

extern “C”

有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern “C”,意思是告诉编译器,将该函数按照C语言规则来编译。
比如:tcmalloc是google用C++实现的一个项目,他提供tcmallc()和tcfree两个接口来使用,但如果是C项目就没办法使用,那么他就使用extern “C”来解决。

extern "C" int Add(int left, int right);
int main()
{
 Add(1,2);
 return 0;
}

链接时报错:error LNK2019: 无法解析的外部符号_Add,该符号在函数 _main 中被引用

重载的底层原理

两个函数Add参数的类型不同,在windows环境下Linux环境下编译器编译完成后的函数名的命名风格也就不同。以下是在VS2013编译器下编译完成map文件中的函数名,可以看出Add命名发生改变,一般是 ?[函数名]@@YAHHH@z(只用函数名和YA后面的格式和@z是固定的,剩下的都是固不定的,它的命名代了返回值的参数类型。(H—int,N—double,X—void)

总的来说:源文件通过编译后,将相同函数名,按照一定的格式,改变成可以区分的,去除了函数在调用时的二义性,从而实现函数的重载。

引用

定义

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间

声明方法:类型& 引用变量名(对象名) = 引用实体

void TestRef()
{
 int a = 10;
 int& ra = a;//<====定义引用类型

 printf("%p\n", &a);
 printf("%p\n", &ra);
}

注意:引用类型必须和引用实体是同种类型的

特性

  1. 引用在定义时必须初始化
  2. 一个变量可以有多个引用
  3. 引用一旦引用一个实体,再不能引用其他实体
void TestRef()
{
 int a = 10;
 // int& ra; // 该条语句编译时会出错
 int& ra = a;
 int& rra = a;
 printf("%p %p %p\n", &a, &ra, &rra);
}

常引用

void TestConstRef()
{
 const int a = 10;
 //int& ra = a; // 该语句编译时会出错,a为常量
 const int& ra = a;
 // int& b = 10; // 该语句编译时会出错,b为常量
 const int& b = 10;
 double d = 12.34;
 //int& rd = d; // 该语句编译时会出错,类型不同
 const int& rd = d;
}

使用场景

  1. 做参数
void Swap(int& left, int& right)
{
 int temp = left;
 left = right;
 right = temp;
}
  1. 做返回类型
int& Count()
{
 static int n = 0;
 n++;
 // ...
 return n;
}

例:

int& Add(int a, int b)
{
 int c = a + b;
 return c;
}
int main()
{
 int& ret = Add(1, 2);
 Add(3, 4);
 cout << "Add(1, 2) is :"<< ret <<endl;
 return 0;
}

注意:如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。

引用和指针的区别

  1. 指针是一个实体,需要分配内存空间。引用只是变量的别名,不需要分配内存空间。
  2. 引用在定义时必须初始化,指针没有要求。
  3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体。
  4. 没有NULL引用,但有NULL指针。
  5. sizeof 引用得到的是所指向的变量(对象)的大小,而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、付费专栏及课程。

余额充值