根据题目我们先来解释一下这两个名词到底是什么意思,避免初学者看到此博客一脸懵逼。
函数重载
函数重载:函数重载是函数的一种特殊情况,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++中函数重载和引用就介绍到这里了,欢迎点评。
阿里嘎多!!!