[TOC]
正文开始之前,首先介绍一下3个关键字对应的英文:重载(overload), 覆盖(override), 隐藏(hide)。
下面我们依次介绍。
- 隐藏(hide),直接看代码
#include <iostream>
using namespace std;
class CB {
public:
void f(int i) {
cout << "CB::f(int)" << endl;
}
};
class CD: public CB {
public:
void f(int i, int j) {
cout << "CD::f(int, int)" << endl;
}
void test() {
f(1);
}
};
int main () {
CB B;
CD D;
B.f(1);
D.test();
return 0;
}
编译出错:error: no matching function for call to ‘CD::f(int)’|
因此,我们得到结论类CD中并不存在f(int) 函数,因为基类void CB::f(int)被子类void CD::f(int, int) 隐藏。
如果把派生CD中成员函数void f(int,int)的声明改成和基类中一样,即f(int),基类中的void f(int)还是一样被覆盖,此时编译不会出错,在函数中test调用的是CD中的f(int)
所以,在基类中的某些函数(e.g., f())如果没有关键字virtual修饰,那么子类中的同名函数(e.g., f(), 形参和返回值可以不同)会将基类中同名函数隐藏。
2. 覆盖(override),对上面代码稍作修改:
#include <iostream>
using namespace std;
class CB {
public:
virtual void f(int i) {
cout << "CB::f(int)" << endl;
}
};
class CD: public CB {
public:
virtual void f(int i) {
cout << "CD::f(int)" << endl;
}
void test() {
f(1);
}
};
int main () {
CB B;
CD D;
CB *C = &D;
CD *E = (CD*) &B;
C->f(3);
E->f(3);
return 0;
}
程序编译成功,运行结果如下:
这是很简单的多态应用,详细可参考上一篇博客. 这样的情况我们成为覆盖,指派生类的虚拟函数覆盖了基类的同名且形参和返回值一样的函数。
因此覆盖需要满足如下两个条件:
- 有virtual关键字,在基类中函数声明的时候加上就可以了
- 基类CB中的函数和派生类CD中的函数要一模一样,什么叫一模一样,函数名,参数,返回类型三个条件。
3. 重载
很多人会将上述两种情况误认为重载,这是因为对重载概念不清晰,我们再次详述重载的概念:
重载(overload):必须在一个域中,函数名称相同但是函数参数不同,重载的作用就是同一个函数有不同的行为,因此不是在一个域中的函数是无法构成重载的,这个是重载的重要特征必须在一个域中,而继承明显是在两个类中了哦,所以上面的想法是不成立的,我们测试的结构也是这样,派生类中的f(int,int)把基类中的f(int)隐藏了。所以,相同的函数名的函数,在基类和派生类中的关系只能是覆盖或者隐藏。