这个讲的有点绕,多看几遍,理解一下,再来总结吧。
函数签名包括函数名和函数参数的个数、顺序以及参数数据类型。
1) 重载
函数重载是指两个函数具有相同的函数名,但是函数参数个数或参数类型不同。函数重载多发生在顶层函数之间或者同一个类中,函数重载不需要构成继承关系。
2) 覆盖
覆盖构成条件和多态构成条件是相同的,覆盖是一种函数间的表现关系,而多态描述的是函数的一种性质,二者所描述的其实是同一种语法现象。
覆盖首先要求有继承关系,其次是要求构成继承关系的两个类中必须具有相同函数签名的成员函数,并且这两个成员函数必须是虚成员函数,具备这两个条件后,派生类中的虚成员函数则会覆盖基类中的同名的虚成员函数。如果我们通过基类指针或引用来调用虚成员函数,则会形成多态。
#include<iostream>
using namespace std;
class base
{
public :
virtual void vir1(){}
virtual void vir2(){}
};
class derived : public base
{
public:
void vir1(){}
void vir2(){}
};
int main()
{
base * p;
p = new derived;
p->vir1();
p->vir2();
delete p;
return 0;
}
3) 遮蔽
函数遮蔽同样要求构成继承关系,构成继承关系的两个类中具有相同函数名的函数,如果这两个函数不够成覆盖关系,则就构成了遮蔽关系。遮蔽理解起来很简单,只要派生类与基类中具有相同函数名(注意不是相同函数签名,只需要相同函数名就可以了)并且不构成覆盖关系即为遮蔽。
遮蔽可以分为两种情况,一种是非虚函数之间,另一种则是虚函数之间。我们通过程序示例来分别介绍这两种遮蔽情况。
以上总结了函数名相同的所有情况,函数名相同利用的好可以为程序设计带来较大的便利,使用的不好则容易误导程序设计人员。一般来讲,函数名相同通常会用在以下几种情况中:
- 顶层函数的函数重载。对于程序设计人员而言,实现功能相同但所处理数据类型不同的函数时,采用函数重载的方式将会带来极大的方便。例如设计一个求绝对值函数,针对整型和double类型各设及一个abs函数,调用时而无需关注参数类型,这样的设计是很方便的。
- 类中的成员函数的重载,这种函数重载和顶层函数重载同样能给我们的程序带来方便。
- 类中的构造函数重载,设计多个构造函数,用于不同的初始化对象方式。
- 在继承层次中为了使用多态特性而采用相同函数签名。
除此之外函数名相同还会导致继承层次中的函数遮蔽,而函数遮蔽这一特性通常会使得程序难以理解,因此建议谨慎使用函数遮蔽机制。