1 函数的重载、重写(重定义)、函数覆盖及隐藏
其实函数重载与函数重写、函数覆盖和函数隐藏不是一个层面上的概念。前者是同一个类内,或者同一个函数作用域内,同名不同参数列表的函数之间的关系。而后三者是基类和派生类函数不同情况下的关系。
1.1 函数重载
正如上文说的函数的重载是指类内部,同名不同参数列表函数之间的关系。如下:
void show();
void show(int);
void show(int , double);
以上是多个同名参数列表不同的函数,这种情况就是函数重载。不同的函数返回值不作为判断函数重载的依据,比如如下两个函数会被判定为函数重定义。
void show();
int show();
编译器错误:“错误(活动) E0311 无法重载仅按返回类型区分的函数”。
不过函数重载要注意的是有默认参数和类型的隐式转换造成的问题,这里需要了解一下编译器是如何选择使用那个版本的函数的。其大致过程是
- 第一步,创建候选函数列表。其中包含与被调用函数的名称相同的函数
- 第二步,使用候选函数列表创建可行函数列表,这些都是参数数目正确的函数,为此有一个隐式转换序列,其中包括实参数类型与相应的形参类型完全匹配的情况。例如,使用float参数的函数调用可以将该参数转换为double,从而与double形参匹配。
- 第三步,确定是否有最佳的可行函数。如果有,则使用它,否则该函数调用出错(没有匹配项或者有多个匹配项都出错)
所以再重载函数的时候要注意有默认参数值和隐式转换,如下:
#include <iostream>
void show()
{
std::cout << "无参数" << std::endl;
}
void show(int n = 1)
{
std::cout << "有参数" << std::endl;
}
void show(double d)
{
std::cout << "有参数 double" << std::endl;
}
void show(double & d)
{
std::cout << "有参数 double 引用" << std::endl;
}
int main()
{
show(); //E0308 有多个 重载函数 "show" 实例与参数列表匹配:
double d = 10;
show(d); //E0308 有多个 重载函数 "show" 实例与参数列表匹配
}
对于有默认参数值的情况不必多说,对于隐式转换则要注意在匹配的第三步编译器确认那些是最佳的。它查看为使函数调用参数与可行的时候选函数的参数匹配所需要进行的转换。通常从最佳到最差的顺序如下所述。
- 完全匹配
- 提升转换(如:char自动转换为int,float自动转换为double)
- 标准转换(如:int转换为char,long转换为double)
- 用户定义的转换(如:类种定义的转换构造函数)
进行完全匹配时,C++允许一些无关紧要的转换,如下表:
实参 | 形参 |
---|---|
Type | Type & |
Type & | Type |
Type[] | Type * |
Type(argument-list) | Type(*)(argument-list) |
Type | const Type |
Type | volatile Type |
Type * | const Type * |
Type * | volatile Type * |
1.2 函数覆盖
这个概念都是描述基类和派生类之间函数关系的。函数覆盖:是基类虚函数在派生类种被重新定义。如:
class Base
{
virtual void show