一、函数重载
在自然语言中,一个词可以有多个意思,人们可以根据上下文来分析它的意思,即该词被重载了。
函数重载:就是指在同一个作用域中,声明了几个作用不同但名称相同的函数。这些同名函数的参数个数,参数类型及参数类型的顺序不同。如:
1.1参数类型不同的函数
void Add(int a, int b)
{
cout << "Add(int a, int b) = " << a + b << endl;
}
void Add(double a, double b)
{
cout << "Add(double a, double b) = " << a + b << endl;
}
int main()
{
Add(1, 2);
Add(1.1, 1.2);
return 0;
}
运行结果:
1.2参数数量不同的函数
void F()
{
cout << "F()" << endl;
}
void F(int a)
{
cout << "F(a)" << endl;
}
int main()
{
F();
F(1);
return 0;
}
运行结果:
注:在函数重载中使用缺省参数,应当注意一下情况。如:
void Func(int a, int b = 2)
{
cout << "Func(int a, int b) = " << a + b << endl;
}
void Func(int a)
{
cout << "Func(int a) = " << a << endl;
}
int main()
{
Func(1,2);
Func(1);
return 0;
}
以上代码,编译器无法识别
1.3参数类型顺序不同的函数
void Func(int a, double b)
{
cout << "Func(int a, double b) = " << a + b << endl;
}
void Func(double a, int b)
{
cout << "Func(double a, int b) = " << a << endl;
}
int main()
{
Func(1.1, 2);
Func(1, 2.2);
return 0;
}
运行结果:
注:如果两个函数函数名和参数是一样的,但返回值的类型不同是无法构成重载的,因为调用时编译器无法区分。
二、引用
引用不是定义了一个新的变量,而是给已经存在的变量取了一个别名(也可以看做是外号、小名),编译器不会开辟新的内存空间,它们是公用了一块内存空间,只是名字不同。
引用的形式:类型& 引用对象名 = 引用实体
int main()
{
int a = 0;
int& b = a;//在这里&不是取地址,而是引用
int& c = a;
return 0;
}
在上述代码中,我们调试可以发现a,b,c的地址是相同的:
因此,我们可以得出结论:只要上述名称中其中一个对象的值发生了改变,其他对象的值也会发生改变。
1.1引用的特性
- 引用在定义时必须初始化
- 同一个变量可以用多个引用
- 引用一旦引用了一个实体,就不能再引用其他实体了
1.2常引用
int main()
{
const int a = 0;
//从const int到int是权限的放大
//int& b = a; //该语句编译时,会发生错误。由于a是常量,因此用非常量引用是非法的
int d = a;//合法,因为这是赋值,不受权限的影响
//从const int到const int是权限的平移
const int& b = a; //该语句合法
int c = 0;
const int s = c;//权限的缩小
return 0;
}
权限可以缩小,权限可以平移,但权限不能放大
int main()
{
int a = 0;
double b = a;//语句合法
double& b = a;//语句非法
const double& c = a;//语句合法
}
上述代码第三句非法是由于,在C++中类型的转换并不是直接进行转换的,而是把a拷贝到一个临时变量中,再进行引用,由于临时变量是一个常量,因此第三句代码非法而第四句代码合法。如图:
1.3引用的使用
1.1做参数
void Swap(int& p1, int& p2)
{
int tmp = p1;
p1= p2;
p2= tmp;
cout << "a = " << p1 << endl;
cout << "b = " << p2 << endl;
}
int main()
{
int a = 0;
int b = 2;
Swap(a, b);
return 0;
}
运行结果:
在C语言中,写Swap函数时需要用到指针,解引用。而在这里只需要用到引用,这是因为Swap参数表中的p1和p2引用的实体分别是实参a和b,由于是引用,因此p1和a指向的是同一块空间p2和b指向的是同一块空间,p1和p2发生改变则a和b就会发生改变。
1.2做返回值
struct SeqList
{
int* a;
};
int& Push(int* a, int i)
{
a[i] = i;
return a[i];
}
int main()
{
struct SeqList s;
s.a = (int*)malloc(sizeof(int) * 5);
Push(s.a, 0) = 0;
Push(s.a, 1) = 10;
Push(s.a, 2) = 20;
cout << s.a[1] << endl;
return 0;
}
运行结果:
注:如果函数返回时,出了函数作用域,如果返回对象还存在(没有还给系统),则可以使用引用返回。但如果已经还给系统了,则必须使用传值返回。因为还给系统后,该函数的内存已经被释放。
1.4引用和指针的区别
引用在语法概念上就是一个别名,并没有独立的空间,和它的引用实体共用一块空间。但在底层实现上,引用实际上是有空间的,因为引用是按照指针的方式实现的。
引用和指针的不同之处:
-
引用在概念上定义一个变量的别名,指针存储一个变量地址
-
引用在定义时必须初始化,但指针并没有要求
-
引用在初始化时引用一个实体后就不能再引用其他实体,但指针可以在任何时候指向任何一个同类型的实体
-
没有NULL引用,但有NULL指针
-
在sizeof中,引用的结果是引用类型的大小,但指针始终是地址空间所占的字节数
-
引用比指针使用起来更加的安全
-
指针需要解引用,但引用是编译器自己处理