这篇文章对多态做一个总结,同时对虚函数、纯虚函数、重载、覆盖、隐藏作相应的总结。
1.1 定义
如果有几个相似而不完全相同的对象,有时人们要求在向他们发出同一消息时,他们的反应各不相同,分别执行不同的操作,这种情况就是多态现象。C++所谓的多态是指,由继承而产生的相关的不同的类,其对象对同一消息会作出不同的响应。在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。
2 虚函数
2.1 定义
虚函数是一种在基类定义为virtual的函数,并在一个或多个派生类中重新定义的函数。
2.2 格式
class 类名{
vitrual 函数声明
};
2.3 规则
- 在基类中用virtual声明成员函数为虚函数。类外实现虚函数时,不必再加virtual;
- 在派生类中重新定义此函数称为覆写,要求函数名,返回类型,函数参数个数及类型全部匹配。并根据派生类的需要重新定义函数体;
- 当一个成员函数被声明为虚函数后,其派生类中完全相同的函数(显示的写出)也为虚函数。可以在其前面加上vitrual以示清晰;
- 定义一个基类对象的指针,并使其指向子类的对象,通过该指针调用虚函数,此时调用的就是指针变量指向对象的同名函数;
- 子类中覆写的函数,可以为任意访问类型,依子类需求决定;
- 只有类中的成员函数才能声明为虚函数,因为虚函数仅适用于与有继承关系的类对象,所以普通函数(包括友元函数)不能声明为虚函数;
- 静态成员函数不能是虚函数,因为静态成员函数不受限于某个对象;
- 内联函数不能是虚函数,因为内联函数不能再运行中动态确定位置;
- 构造函数不能是虚函数,析构函数可以是虚函数,而且通常声明为虚函数(析构函数比较特殊,因为派生类的析构函数跟基类的析构函数名称不一样,但是构成覆盖,这里编译器做了特殊处理);
有关虚函数表的介绍:虚函数表
3 纯虚函数
3.1 格式
class 类名{
vitrual 函数声明=0;
};
3.2 规则
- 含有纯虚函数的类,称为抽象基类,不可实例化。即不能创建对象,存在的意义就是被继承,提供族类的公共接口,java中称为interface。
- 纯虚函数只有声明,没有实现,被“初始化”为0。
- 如果一个类中声明了纯虚函数,而在派生类中没有对该函数定义,则该虚函数在派生类中仍然为纯虚函数,派生类仍然为纯虚基类。
4 多态
多态可以分为静多态和动多态,如下图所示。
图 1 多态
4.1 静多态
静多态是在编译的时候就确定调用函数的类型,函数重载就是一个典型的静多态。
函数重载的规则:(1)函数名相同;(2)参数的个数不同、参数的类型不同、参数的顺序不同,均可构成重载;(3)返回类型不同不可以构成重载;(4)相同的范围(在同一个类中)。
4.2 动多态
在运行的时候才确定调用哪个函数,动态绑定。实质是子类重新定义了父类的虚函数,父类的指针根据赋给它的不同子类的指针,动态的调用属于子类的该函数,这样的函数调用在编译期间无法确定。这里需要引入一个概念:覆盖。覆盖是指派生类中重新定义父类中的函数,其函数名、参数列表、返回类型必须同父类中的相对应被覆盖的函数严格一致,只有函数体不同。
覆盖的规则:(1)函数名相同;(2)参数相同;(3)基类函数必须有virtual关键字;
上面已经提及重载和覆盖,接着说一下隐藏:隐藏是指派生类的函数屏蔽了与其同名的基类函数。
规则:(1)如果派生类的函数与基类的函数同名,但是参数不同,此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆);(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆);
加个图:
图2 重载、覆盖和重定义的区别
Reference :