重写(Override)与隐藏(hide)的区别
重写必须满⾜的条件:
1. 基类中的函数使⽤virtual修饰,即基类中的函数为虚函数;
2. 派⽣类中与基类中的这个virtual函数要有相同的函数原型(即:返回类型相同、函数名相同、形参列表相同);
下⾯我们看个简单的程序:
#include <iostream>
using std::cout;
using std::endl;
class Person
{
public:
virtual void Study()
{
凉薯的做法
cout << "这是基类中的⽅法" << endl;
}
};
class Man : public Person
{
public:
virtual void Study()
{
cout << "这是派⽣类中的⽅法" << endl;
}
};
int main(void)
{
Person *p = new Man;
p -> Study(); // 输出结果:这是派⽣类中的⽅法
return 0;
}
Man类中的Study()函数对Person类中的Study()函数进⾏了重写。
也许有些⼈认为:返回类型可以不同,这个我们可以做个测试,就是将Man类中的Study()⽅法改为返回值为int类型:
virtual void Study()
{
cout << "这是派⽣类中的⽅法" << endl;
return 0;
}
再次编译,我们会发现,程序编译都不能通过,提⽰返回类型冲突,重写错误。
所以,重写(Override)或覆盖只会发⽣在多态中。对于基类中的⾮virtual函数,在派⽣类中重新定义只会导致隐藏。
隐藏:指的是派⽣类中的函数屏蔽了基类中的函数。
隐藏的规则:
1. 对于基类中的⾮virtual函数,如果派⽣类中存在和基类中相同的函数名,⽽不管返回值和形参列表是否相等;都会导致基类中的所有同名函数被派⽣类隐藏;
2. 对于基类中的virtual函数,如果派⽣类中存在和基类中相同的函数名,⽽且形参列表不同,就会导
致基类中的所有同名的virtual函数被派⽣类隐藏;
注意:如果派⽣类中的函数和基类中的同名的virtual函数具有相同的形参列表和不同的返回值,那么将不会隐藏基类中的函数,直接导致编译错误(原因:编译器此时会认为你是在重写⽅法,⽽不是隐藏,只是返回类型写错了)。
下⾯我们看⼀个简单的程序:
#include <iostream>
using std::cout;
using std::endl;
class Person
小狗包弟
{
public:
void Eat()
神奇的动物{
cout << "这是基类中的Eat⽅法" << endl;
}
void Work()
{
cout << "这是基类中不带参数、返回值为void的Work函数" << endl;
}
void Work(int a)
{
cout << "这是基类中带⼀个参数、返回值为void的Work函数" << endl;
}
给谁的一封信
virtual void Study()
{
cout << "这是基类中不带参数的虚⽅法" << endl;
}
virtual void Study(int a)
{
行云流水打一动物cout << "这是基类中有⼀个参数的虚⽅法" << endl;
}
};
class Man : public Person
{
public:
int Work()
{
cout << "这是派⽣类中不带参数、返回值为int的Work函数" << endl;
return 0;
}
virtual void Study(int a, int b)
{
cout << "这是派⽣类中虚的⽅法" << endl;
}
};
int main(void)
{
Man m;法西斯
m.Eat();
// m.Study(); //该函数已被派⽣类中定义的Study(int a, int b)隐藏,调⽤会导致编译错误 // m.Study(1); //该函数已被派⽣类中定义的Study(int a, int b)隐藏,调⽤会导致编译错误 m.Study(1, 2);
m.Work();金华万达
// m.Work(1); //该函数已被派⽣类隐藏中定义的Work()隐藏,调⽤会导致编译错误
return 0;
}
分析:在派⽣类中,没有定义Eat()⽅法,所以派⽣类可以正常的调⽤基类中的Eat()⽅法,但是后⾯的筷子手工作品
Study()⽅法,在派⽣类中对其进⾏了定义,虽然函数原型不同,但也隐藏了基类中的所有名为Study()的函数,需要注意的是:如果派⽣类中的函数和基类中的同名的virtual函数具有相同的形参列表和不同的返回值,那么将不会隐藏基类中的函数,直接导致编译错误(原因:编译器此时会认为你是在重写⽅法,⽽不是隐藏,只是返回类型写错了)。关于这⼀点,你可以在Man中添加⼀个int Study()函数试⼀下。对于Work()函数,同样是由于在派⽣类中定义了⼀个同名的函数,导致基类中重载的⼀组Work()函数都被屏蔽。
对于隐藏,我们从字⾯意思也可以看出,只是将基类中的同名的函数屏蔽了,并没有将其销毁,所以我们还是可以对其进⾏调⽤的。
主要有以下三种⽅法:
1. 在派⽣类中的函数中调⽤基类中的同名函数,⽐如:
virtual void Study()
{
Person::Study();
}
2. 在派⽣类中定义函数的前⾯使⽤using关键字显式地声明;
using Person::Study;
virtual void Study()
{
cout << "这是基类中不带参数的虚⽅法" << endl;
}
3. 采⽤派⽣类对象.基类名::基类中的⽅法;直接调⽤;例如:对于上⾯的程序,如果我们要调⽤基类中的Study()⽅法,我们可以这样才调⽤:m.Person::Study();
通过这三种⽅式,我们就可以访问被派⽣类屏蔽了的基类中定义的函数。
总结:所谓重写(或叫覆盖),指的是派⽣类对基类中的虚函数进⾏⽅法体的改写(要求函数原型相同);⽽隐藏指的是,派⽣类中的函数屏蔽了基类中同名的所有函数。(对virtual函数,要求函数名相同,形参列表不同;对 ⾮virtual函数,函数名相同即可)。注意:在继承中不涉及重载的概念,因为重载最基本的要求是:在相同的作⽤域中,⽽继承显然属于不同作⽤域。