浅谈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;
}

在代码主函数中可以看到,我们定义了三个函数名相同的函数,只有参数类型不同罢了,这时编译器并没有报错。这时,程序会根据实参不同的数据类型调用相对应的函数,这就是函数重载。至于为什么会调用相对应的的函数,后面我们在分析(this指针和_cedel调用约定)
这里写图片描述
从图片中我们可以得到一些结论
在函数重载中,参数的类型和个数都可以不同,但不能只有函数的类型不同而参数的个数和类型相同。如果写成上述形式的话,编译器无法判别应该调用哪一个函数。因此,在函数重载中,我们应注意重载函数的参数类型,参数个数或参数顺序至少有一种不同,函数返回值类型可以相同也可以不相同。
这里给读者提供一个大牛对C++函数重载和各种调用约定的深入理解,有兴趣的人可以看看。
函数重载:http://www.cnblogs.com/skynet/archive/2010/09/05/1818636.html
调用约定:http://blog.csdn.net/lioncolumn/article/details/10376891

引用

引用:在这里它不是一个动词,它的作用是为一个变量起一个别名。既然是别名,那么就不需要给别名重新开辟一块内存空间,则以下例子中a和Ta共用同一块内存空间。

例如:

int a=10;  //定义a是一个int类变量
int& Ta=a;  //声明Ta是a的“引用”,变量Ta具有变量a的地址
//a=10   Ta=10

大家仔细观察会发现这里的引用在变量名前加了一个“&”,这里的“&”代表的不是地址,而是引用声明符

char &Ta=a;   //这里的&是引用声明符
char *p=&a;   //这里的&是取地址符

那怎么来理解这句话呢?以上声明了Ta是a的引用,即Ta是a的别名,那我们就可以这样来表达这串代码的含义:通过Ta来引用a。

在引用变量时应注意以下几点:
⑴引用不是一种独立的数据类型,对引用只有声明么有定义。使用时必须先定义一个变量,在对这个变量进行引用(别名)。
⑵声明一个引用时,必须同时使之初始化。当引用作为函数形参时不必再声明中初始化,他是在函数调用时自动实现的,即作为形参的引用是实参的别名。(下面我会提到在函数中引用作为形参)
这里写图片描述
⑶声明一个引用后就不能在作为另一个变量的声明。

看个例子

⑷不能建立引用数组。
这里写图片描述
⑸不能建立引用的引用,也没有引用的指针,例如:
这里写图片描述

⑹可以取引用的地址

int main()
{
   int *p;
   int a=10;
   int &Ta=a;
   p=&Ta    //把变量a的地址&a赋给指针P,即&Ta就是变量a的地址
}

⑺区别引用声明符和地址运算符

int main()
{
     int a=10;
     int &Ta=a;  //声明Ta是a的引用
     cout<<&Ta<<endl;   //打印a的地址,这里的&Ta不是引用

接下来我们讲一讲引用作为函数参数是怎么用的吧。
首先我们先回顾一下在C语言中交换两个数是怎么交换的吧。
交换两数的值有两种方法,一种是传值,一种是传址。

#include <iostream>
using namespace std;
//传值交换
void Swap1(int left, int right)
{
    int temp = 0;
    temp = left;
    left = right;
    right = temp;
}
//传址交换
void Swap2(int* left, int* right)
{
    int temp = 0;
    temp=*left;
    *left = *right;
    *right = temp;
}
int main()
{
    int a = 10;
    int b = 20;
    Swap1(a, b);
    cout << a <<' '<< b << endl;
    Swap2(&a, &b);
    cout << a << ' ' << b << endl;
    return 0;
}

这里我们附上上面程序得到的结果
从结果可以看来,传值并没有得到我们想要的结果,传址就可以,这是为什么呢?
这是因为在进行值传递时,传递是单向的,并且在调用函数时,系统为形参开辟一块临时空间,和实参并不在同一个存储单元,如果在执行函数期间形参发生变化,那么变化后的形参值并不会返回给实参。
优点:避免了函数调用的副作用
缺点:无法改变形参的值
而在进行传地址操作时,形参是指针变量,实参是一个变量的地址,调用函数时,指针变量得到实参的地址,此时,形参和实参都指向同一块地址空间,因此,在进行传址的情况下是能够交换两个数的。
指针虽然能够得到我们想要的结果但不是很形象友好,如果对指针不熟练那就可能造成意想不到的后果,那么,有没有一种既可以进行值传递,又能够达到址传递的效果呢?
聪明的科学家就想到了用引用来解决这个问题。

void Swap(int& left, int& right) //这里的&是引用声明符
{
    int temp = left;
    left = right;
    right = temp;
}
int main()
{
    int a = 10,b = 20;
    int& Ta = a;
    int& Tb = b;
    Swap(Ta, Tb);
    cout << a << ' ' << b << endl;
    return 0;

这里怎么理解呢。首先,Ta 和 Tb 无疑是变量a和b的别名,在进行函数传参时,把实参 a 和 b 的地址传给了形参 left 和 right 。这样实参和形参得到的就是同一块地址空间,这样能够交换两个数也就是很容易理解了。

上面是引用的应用场景之一,引用还可以作为函数返回值

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

看到这里有人会问了,指针和引用到底有什么区别,结果都是能够交换两个数,你说引用可以避免指针的缺陷,到底是什么意思呢?
接下来我们就来讲一讲指针和引用的相同点和不同点:

这里写图片描述

相同点:从反汇编里面我们可以看出指针和引用在在底层里没有什么区别,都是按照指针的方式来实现的。
不同点
①引用在定义时必须初始化,指针没有要求
②一旦一个引用被初始化为指向一个对象,就不能再指向其他对象,而指针可以在任何时候指向任何一个同类型对象
③没有NULL引用,但有NULL指针
④在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址*空间所占字节个数
⑤引用自加改变变量的内容,指针自加改变了指针指向
⑥有多级指针,但是没有多级引用
⑦指针需要手动寻址,引用通过编译器实现寻址
⑧引用比指针使用起来相对更安全
好了 , 咱们C++中函数重载和引用就介绍到这里了,欢迎点评。
阿里嘎多!!!

猜你喜欢

转载自blog.csdn.net/qq_39412582/article/details/80626411