大家好:
衷心希望各位点赞。
您的问题请留在评论区,我会及时回答。
多态的基本概念
多态是C++面向对象三大特性之一(多态、继承、封装)
多态分为两类:
静态多态:函数重载和运算符重载属于静态多态,复用函数名。
动态多态:通过派生类和虚函数实现运行时多态。
静态多态和动态多态的区别:
静态多态的函数地址早绑定——编译阶段确定函数地址。
动态多态的函数地址晚绑定——运行阶段确定函数地址。
下面通过案例讲解多态:
#include <iostream>
#include <Windows.h>
using namespace std;
class Animal
{
public:
void speak()
{
cout << "动物在说话" << endl;
}
};
class Cat : public Animal
{
public:
// 重写父类中的函数
void speak()
{
cout << "小猫在说话" << endl;
}
};
// 执行说话的函数
void doSpeak(Animal& animal)
{
animal.speak();
}
int main(void)
{
Cat cat;
doSpeak(cat); // 父类引用接收子类对象
system("pause");
return 0;
}
运行截图:
全局函数doSpeak()在编译阶段就确定了它的地址——函数地址早绑定,即使形参传入基类Animal的任何子类,子类已经重写了基类的speak()函数。doSpeak() 函数只会调用基类Animal的speak()函数。但是,我们想执行这行代码doSpeak(cat)的时候,输出“小猫在说话”。即:在运行阶段,根据函数doSpeak()传入的实参类型,再去决定具体执行哪个类的成员函数。
如果想要实现“小猫在说话”,那么函数地址就不能早绑定,必须在程序运行阶段进行绑定,即:动态多态的函数地址晚绑定——运行阶段确定函数地址。
在父类的成员函数前加上关键字 virtual ,使其变成虚函数,并且在子类中重写父类的虚函数即可。
#include <iostream>
#include <Windows.h>
using namespace std;
class Animal
{
public:
virtual void speak() // 虚函数
{
cout << "动物在说话" << endl;
}
};
class Cat : public Animal
{
public:
// 重写父类中的虚函数
virtual void speak()
{
cout << "小猫在说话" << endl;
}
};
class Dog : public Animal
{
// 重写父类中的虚函数
virtual void speak()
{
cout << "小狗在说话" << endl;
}
};
// 执行说话的函数
void doSpeak(Animal& animal)
{
// 在运行阶段,才能确定函数speak()的地址,即:根据实参类型,才能确定执行哪个speak()函数
animal.speak();
}
int main(void)
{
Cat cat;
doSpeak(cat); // 调用类Cat的speak()
cout << "----------" << endl;
Dog dog;
doSpeak(dog); // 调用类Dog的speak()
system("pause");
return 0;
}
运行截图:
实现了:在程序运行时,根据实参类型,决定执行哪一个子类重写的函数。程序执行到doSpeak(cat)这行代码时,编译器检测到实参类型是Cat类,就会调用Cat类的speak()函数。程序执行到doSpeak(dog)这行代码时,编译器检测到实参类型是Dog类,就会调用Dog类的speak()函数。
注意:子类重写父类的虚函数,可以省略 virtual 关键字。
总结
动态满足条件:
1、有继承关系
2、子类重写父类的虚函数
函数重写:函数首部完全相同,函数体不同,函数重写发生在子类中。
动态多态的使用
父类的指针或引用接收子类对象,调用子类重写的父类函数,就会发生动态多态。