一、多态介绍
- 面向对象的核心思想是多态性,其含义是“多种形式”
- 概念:在子类覆盖了父类函数的情况下,用父类的指针(或引用)调用子类对象,或者通过父类指针调用覆盖函数的时候(动态绑定),实际上调用的是子类的覆盖版本,这种现象叫做多态
- 注意事项:
- 只有用父类的指针(或引用)调用子类对象多态才会产生,非指针/引用不会产生多态
- 且只有用父类的指针(或引用)调用虚函数才会产生多态,调用非虚函数不会产生多态效果
- 运行时解析:
当我们使用基类的引用或指针调用基类中定义的一个虚函数时,我们并不知道该函数真正作用的对象是什么类型,因为它可能是一个基类的对象也可能是一个派生类的对象
如果该函数是虚函数,则直到运行时才会决定到底执行哪个版本。非虚函数的调用在编译时进行绑定的,类似的,通过对象进行的函数(虚函数或非虚函数)调用也在编译时绑定
二、多态的条件
- 父子类之间有覆盖关系
- 基类必须通过引用或指针指向子类,然后再调用虚函数,此时就可以实现多态
三、演示案例
class A
{
public:
//虚函数
virtual void show()const { cout << "A1 "; }
void show2()const { cout << "A2\n"; }
};
class B :public A
{
public:
//虚函数
void show()const { cout << "B1 "; }
void show2()const { cout << "B2\n"; }
};
void printfShow(A const& data)
{
data.show();
data.show2();
}
int main()
{
A a;
B b;
printfShow(a);
printfShow(b);
return 0;
}
运行结果:
结果分析:
- ①printfShow(a):因为传入的是A类对象,所以调用的是A类中的show()和show2()方法,这个没什么稀奇的,看下面
- ②printfShow(b):传入的是B类对象,而B类是A的派生类
- 所以调用show()时,由于show是虚函数,所以此时对于show的调用取决于引用所指的对象类型(此处为B,所以调用B的show函数,这就是动态绑定与多态的效果)
- 调用show2()时,因为show2()不是虚函数,所以不会有多态的效果,此时对函数的调用取决于引用的类型(A类型),所以调用A类的show2()方法这个原理就是前面介绍“派生类向基类转换”的文章的知识点.
四、virtual函数的缺省参数值是静态绑定的
五、多态的实现方式(面试)
- 1.必须有继承关系
- 2.父子类之间有重写(覆盖)
- 3.父类的指针指向于子类,或父类的引用指向于子类
- 4.通过父类的指针或引用调用成员方法,会实现不同的效果