在面向对象的开发过程中,经常出现类的继承,这里面出现的成员函数的重载(overload)、覆盖(override)与隐藏(hidden)很容易混淆。
首先澄清这3个概念
1. 重载
1)发生在同类中;
2)函数名相同;
3)参数不同;
4)可加可不加virtural关键字
2. 重写(覆盖)
1)发生在父类与子类中;
2)函数名相同;
3)参数相同;
4)必须加virtural关键字
3. 隐藏
1)派生类的函数与基类的函数同名,但不同参。此时,无论基类是否有无virtural关键字,基类的函数将被隐藏;(与重载不同的是:重载发生在同类中)
2)派生类的函数与基类的函数同名,且参数相同,但基类中无virtural关键字。此时,基类的函数被隐藏(与重写不同的是:重写必须加virtural关键字)
下面将通过代码来说明:
#include <iostream>
using namespace std;
class Person
{
public:
virtual void vf(float x) {
cout << "Person::vf(float) " << x << endl;
}
void g(float x) {
cout << "Person::g(float) " << x << endl;
}
void h(float x) {
cout << "Person::h(float) " << x << endl;
}
};
class Teacher: public Person
{
public:
virtual void vf(float x) {
cout << "Teacher::vf(float) " << x << endl;
}
void g(int x) {
cout << "Teacher::g(int) " << x << endl;
}
void h(float x) {
cout << "Teacher::h(float) " << x << endl;
}
};
int main()
{
Derived d;
Base *pb = &d; // 基类的指针指向派生类的对象
Derived *pd = &d; // 派生类的指针指向派生类的对象
pb->vf(3.14); // 重写 调用派生类函数
pd->vf(3.14); //
pb->g(3.14);
pd->g(3.14);
pb->h(3.14);
pd->h(3.14);
return 0;
}
结果输出:
Teacher::vf(float) 3.14
Teacher::vf(float) 3.14
Person::g(float) 3.14
Teacher::g(int) 3
Person::h(float) 3.14
Teacher::h(float) 3.14
分析:
由于vf函数是virtual函数,调用它的对象类型为动态类型即指针指向的类型(动态联编),所以调用的是子类的类型;
由于h函数和g函数是非virtual函数,调用它的对象类型为静态类型即父类(静态联编),所以调用的是父类的对象
总结:
IF 子类的函数与父类的名称相同,但是参数不同
父类函数被隐藏
ELSE IF 子类函数与父类函数的名称相同&&参数也相同&&但是父类函数没有virtual
父类函数被隐藏
ELSE IF 子类函数与父类函数的名称相同&&参数也相同&&但是父类函数有virtual
父类函数被覆盖(重写)