33.C++中的重载、重写(覆盖)和隐藏的区别
33.C++中的重载、重写(覆盖)和隐藏的区别
(1)重载(overload)
重载是指在同一范围定义中的同名成员函数才存在重载关系。主要特点是函数名相同,参数类型和数目有所不同,不能出现参数个数和类型均相同,仅仅依靠返回值不同来区分的函数。重载和函数成员是否是虚函数无关。举个例子:
class A
{
...
virtual int fun();
void fun(int);
void fun(double, double);
static int fun(char);
...
}
(2)重写(覆盖)(override)
重写指的是在派生类中覆盖基类中的同名函数,重写就是重写函数体,要求基类函数必须是虚函数且:
- 与基类的虚函数有相同的参数个数
- 与基类的虚函数有相同的参数类型
- 与基类的虚函数有相同的返回值类型
举个例子:
//父类
class A{
public:
virtual int fun(int a){}
}
//子类
class B : public A{
public:
//重写,一般加override可以确保是重写父类的函数
virtual int fun(int a) override{}
}
重载与重写的区别:
- 重写是父类和子类之间的垂直关系,重载是不同函数之间的水平关系
- 重写要求参数列表相同,重载则要求参数列表不同,返回值不要求
- 重写关系中,调用方法根据对象类型决定,重载根据调用时实参表与形参表的对应关系来选择函数体
(3)隐藏(hide)
隐藏指的是某些情况下,派生类中的函数屏蔽了基类中的同名函数,包括以下情况:
- 两个函数参数相同,但是基类函数不是虚函数。和重写的区别在于基类函数是否是虚函数。举个例子:
//父类
class A
{
public:
void fun(int a)
{
cout << "A中的fun函数" << endl;
}
};
//子类
class B : public A
{
public:
//隐藏父类的fun函数
void fun(int a)
{
cout << "B中的fun函数" << endl;
}
};
int main()
{
B b;
b.fun(2); //调用的是B中的fun函数
b.A::fun(2); //调用A中fun函数
return 0;
}
隐藏和重写都是面向对象编程中的关键字,它们的区别在于:
1.参数列表不同:隐藏函数和被隐藏函数参数列表可以相同或不同,但函数名必须相同;而重写函数和被重写函数参数列表必须相同。
2.执行方式不同:隐藏函数会隐藏基类中的同名函数,而重写函数会覆盖基类中的同名函数。
- 两个函数参数不同,无论基类函数是不是虚函数,都会被隐藏。和重载的区别在于两个函数不在同一个类中。举个例子:
//父类
class A
{
public:
virtual void fun(int a)
{
cout << "A中的fun函数" << endl;
}
};
//子类
class B : public A
{
public:
//隐藏父类的fun函数
virtual void fun(char* a)
{
cout << "A中的fun函数" << endl;
}
};
int main()
{
B b;
b.fun(2); //报错,调用的是B中的fun函数,参数类型不对
b.A::fun(2); //调用A中fun函数
return 0;
}
补充:
// 父类
class A
{
public:
virtual void fun(int a)
{ // 虚函数
cout << "This is A fun " << a << endl;
}
void add(int a, int b)
{
cout << "This is A add " << a + b << endl;
}
};
// 子类
class B: public A
{
public:
void fun(int a) override
{ // 覆盖
cout << "this is B fun " << a << endl;
}
void add(int a)
{ // 隐藏
cout << "This is B add " << a + a << endl;
}
};
int main()
{
// 基类指针指向派生类对象时,基类指针可以直接调用到派生类的覆盖函数,也可以通过 :: 调用到基类被覆盖
// 的虚函数;而基类指针只能调用基类的被隐藏函数,无法识别派生类中的隐藏函数。
A *p = new B();
p->fun(1); // 调用子类 fun 覆盖函数
p->A::fun(1); // 调用父类 fun
p->add(1, 2);
// p->add(1); // 错误,识别的是 A 类中的 add 函数,参数不匹配
// p->B::add(1); // 错误,无法识别子类 add 函数
return 0;
}