一、三者的定义
1.重载
重载分为普通函数重载、运算符重载和类型重载,在这里我们只介绍普通函数重载,包括全局作用域下的函数重载和类作用域下的函数重载。
(1)函数名相同
(2)参数列表相同(包括参数个数、参数类型和参数顺序)
(3)属于同一作用域(必须是在同一个类中的成员函数或者均为全局函数,即基类和派生类中的同名函数不可能构成重载)
2.覆盖
(1)函数名相同
(2)发生在基类和派生类之间(这里的基类可能不是直接基类)
(3)基类的成员函数必须定义为虚函数(必须用virtual修饰),派生类中的成员函数可以不用virtual修饰(因为会自动从基类继承virtual特性)
3.隐藏
(1)函数名相同
(2)发生在基类和派生类之间
(3)基类中的成员函数没有被virtual修饰,此时不管派生类中的成员函数是否与基类成员函数列表相同,两者都构成隐藏关系
(4)基类的中成员函数被virtual修饰,但是此时派生类中的成员函数和基类成员函数列表不同,两者构成隐藏关系
二、举例说明三者的区别
下面以一个具体的例子来对以上三者进行说明:
class Base
{
public:
Base() :mem(0)
{
}
virtual int memfun() //1
{
cout << "Base::memfun()" << endl;
return 0;
}
protected:
int mem;
};
class Derive1 :public Base
{
public:
Derive1(int i = 0) :mem(i)
{
}
int memfun(int a) //2
{
cout<<"Derive1::memfun()"<<endl;
return a;
}
virtual void f2() //3
{
cout << "Derived::f2()" << endl;
}
protected:
int mem;
};
class Derive2 :public Derive1
{
public:
int memfun() //4
{
cout << "Derive2::memfun()" << endl;
return 1;
}
int memfun(int a) //5
{
cout << "Derive2::memfun(int)" << endl;
return 3;
}
void f2() //6
{
cout << "Derive2::f2()" << endl;
}
};
这个例子比较复杂,我们先来梳理一下各个类的内存布局情况:
(1).1和2构成隐藏关系,2隐藏1.即通过Derive1的对象无法调用无参数的memfun函数。
(2).1和4构成覆盖关系,因为类Derive2的间接基类为Base,且Derive2中的memfun()函数和Base的memfun()函数满足上面所说的构成覆盖关系的特点。
(3).1和5构成隐藏关系,5将1隐藏了。即通过Derive2的对象无法调用无参数的memfun函数
(4).2和4、2和5均构成隐藏关系
(5).4和5构成重载关系
(6).3和6构成覆盖关系
下面根据上面类的定义,说明一下如何调用以上函数:
int main(void)
{
Base bobj;
Derive1 d1obj;
Derive2 d2obj;
Base *bp1 = &bobj;
Base *bp2 = &d1obj;
Base *bp3 = &d2obj;
bp1->memfun(); //Base::memfun
bp2->memfun(); //Base::memfun
bp3->memfun(); //Derive2::memfun
Derive1 *d1p = &d1obj;
Derive2 *d2p = &d2obj;
//bp2->f2(); //错误,Base没有名为f2的成员函数
d1p->f2(); //调用D1::f2
d2p->f2(); //调用Derive2::f2
Base*p1 = &d2obj;
Derive1 *p2 = &d2obj;
Derive2 *p3 = &d2obj;
//p1->memfun(42); //错误,Base中没有一个接受int的memfun
p2->memfun(32); //静态绑定,调用Derived::memfcn(int)
p3->memfun(23); //静态绑定,调用Derive2::memfcn(int)
return 0;
}