【转载】重载 重写(覆盖) 重定义(隐藏)
一、重载(overload)
指函数名相同,但是它的参数表列个数或顺序,类型不同。但是不能靠返回类型来判断。
(1)相同的范围(在同一个作用域中) ;
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无。
(5)返回值可以不同;
二、重写(也称为覆盖 override)
是指派生类重新定义基类的虚函数,特征是:
(1)不在同一个作用域(分别位于派生类与基类) ;
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有 virtual 关键字,或者是override,但不能是 static 的 。
(5)返回值相同(或是协变),否则报错;有关 协变 的概念见 请见另一篇文章
(6)重写函数的访问修饰符可以不同。尽管 virtual 是 private 的,派生类中重写改写为 public,protected 也是可以的
三、重定义(也成隐藏)
(1)不在同一个作用域(分别位于派生类与基类) ;
(2)函数名字相同;
(3)返回值可以不同;
(4)参数不同。此时,不论有无 virtual 关键字,基类的函数将被隐藏(注意别与重载混淆) 。
(5)参数相同,但是基类函数没有 virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆) 。
即:如果派生类的函数与基类的函数同名,但是参数不同,此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆);如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字,此时,基类的函数被隐藏(注意别与覆盖混淆)。
四、重载与重写的区别
(1)方法的重写是子类和父类之间的关系,是垂直关系;方法的重载是同一个类中方法之间的关 系,是水平关系。
(2)重写要求参数列表相同;重载要求参数列表不同。
(3)重写关系中,调用那个方法体,是根据对象的类型(对象对应存储空间类型)来决定;重载关系,是根据调用时的实参表与形参表来选择方法体的。
(4)重载,在编译期,编译器就根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数,从而实现对其地址的绑定,它与多态无关;重写,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,因而这样的函数调用在编译期间是无法确定的,而是在运行期绑定的,和多态真正相关。
如果基类有某个函数的多个重载(overload)版本,而你在派生类中重写(override)了基类中的一个或多个函数版本,或是在派生类中重新添加了新的函数版本(函数名相同,参数不同),则所有基类的重载版本都被屏蔽,在这里我们称之为隐藏hide。所以,在一般情况下,你想在派生类中使用新的函数版本又想使用基类的函数版本时,你应该在派生类中重写基类中的所有重载版本。你若是不想重写基类的重载的函数版本,则必须显式声明基类名字空间作用域。
class A
{
public:
void fun1()
{
cout<<"A:fun1"<<endl;
}
};
class B:public A
{
public:
void fun1(int i)
{
cout<<"B:fun1"<<endl;
}
};
int main(void)
{
A* ap=new B;
B* bp=(B*)ap;
ap->fun1();
bp->fun1(); //这里编译报错
return 0;
}
编译结果:error C2660: “B::fun1”: 函数不接受0 个参数
分析:出现上述情况是因为类B中有重定义fun1函数,导致类A中的所有fun1函数都被隐藏了,所以执行bp->fun1()时,根本无法调用到类A中的void fun1(),实际上是调用void fun1(int i),故会提示上述差错信息。
class A
{
public:
virtual void fun1()
{
cout<<"A:fun1"<<endl;
}
};
class B:public A
{
public:
void fun1(int i)
{
cout<<"B:fun1 int"<<endl;
}
};
int main(void)
{
A* ap=new B;
B* bp=(B*)ap;
ap->fun1();
bp->fun1();
return 0;
}
编译结果:与上例相同
class A
{
public:
void fun1()
{
cout<<"A:fun1"<<endl;
}
};
class B:public A
{
public:
void fun1()
{
cout<<"B:fun1"<<endl;
}
};
int main(void)
{
A* ap=new B;
B* bp=(B*)ap;
ap->fun1();
bp->fun1();
return 0;
}
执行结果:
A:fun1
B:fun1
分析:子类同名函数,参数相同,但基类函数没有virtual,这个时候是隐藏。用子类的指针只能访问子类的那个fun1,不能访问继承自基类的fun1,其实它仍然存在与基类的代码段中,因为用A类型指针能头访问它。这也是隐藏名字的由来,基类的fun1对子类指针隐藏了,但仍然存在,要通过基类指针访问。
浙公网安备 33010602011771号