C++之中的重载、覆盖、隐藏
- 重载
- 覆盖
- 重载与覆盖的区别
- 相关代码
- 隐藏
重载
重载是指函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数。在同一可访问区域内被声明的几个具有不同参数列表(参数类型、个数、顺序不同)的同名函数,程序会根据不同的参数列来确定具体调用哪个函数。对于重载函数的调用,在编译期间就已经确定,是静态的,它们的地址在编译期间就绑定了与多态无关。
注意:重载不关心函数的返回值类型
特征:
(1)相同的范围(在同一个类中)
(2)函数名字相同
(3)参数不同
(4)virtual 关键字可有可无
覆盖
覆盖是指派生类中存在重新定义基类的函数,其函数名、参数列、返回值类型必须同负类中的相对应被覆盖的函数严格一致,覆盖函数和被覆盖函数只有函数体不同,当派生类对象调用子类中该同名函数时会自动调用子类中的覆盖版本,而不是负类中的被覆盖函数版本,它和多态真正相关。当子类重新定义了负类的虚函数后,负类指针根据赋给它的不同的子类指针,动态地调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的。。
覆盖特征
(1)不同的范围(分别位于派生类与基类)
(2)函数名字相同
(3)参数相同
(4)基类函数必须有virtual关键字
重载与覆盖的区别
(1)覆盖是子类与父类之间的关系,是垂直关系;重载是同一个类中方法之间的关系,是水平关系
(2)覆盖只能由一个方法,或只能由一堆方法产生关系:方法的重载是多个方法之间的关系。
(3)覆盖要求参数列表相同;重载要求参数列表不同
(4)覆盖关系中,调用方法体是根据对象的类型(对象对应存储空间类型)来决定的,重载关系是根据调用时的实参表与形参表来选择方法体的
相关代码
// Base::f(int) 与 Base::f(float)相互重载
// Base::g(void) 被Derived::g(void)覆盖
#include<iostream>
using namespace std;
class Base
{
public:
void f( int x )
{
cout << "Base::f( int )" << x << endl;
}
void f(float x )
{
cout << "Base::f( float )" << x << endl;
}
virtual void g( void )
{
cout << "Base::g( void )" << endl;
}
};
class Derived: public Base
{
public:
virtual void g( void )
{
cout << "Derived::g( void )" << endl;
}
};
int main()
{
Derived d;
Base *pb = &d;
pb->f( 42 );
pb->f( 3.14f );
pb->g();
return 0;
}
隐藏
隐藏是指派生类的函数屏蔽了与其同名的基类函数,规则如下
(1)如果派生类的函数与基类的函数同名,但是参数不同,则不论有无virtual关键字,基类的函数都将被隐藏
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字,此时基类的函数被隐藏
在调用一个类的成员函数时,编译器会沿着类的继承链逐级地向上查找函数的定义,如果找到了就停止查找了,所以,如果一个派生类和一个基类都存在同名(暂时不论参数是否相同)的函数,而编译器最终选择了在派生类中的函数,那么久说这个派生类的成员函数“隐藏”了基类的成员函数,也就是组织了编译器继续向上查找函数的定义。
隐藏关系:
(1)必须分别位于派生类和基类中
(2)必须同名
(3)参数不同的时候本身已经不构成覆盖关系了,所以此时是否是virtual函数已经不重要了
(4)参数相同的时候,看是否有virtual关键字,有的话就是覆盖关系,没有的时候就是隐藏关系了。