环境 : vs2017
C++多态从实现的角度划分为:编译时多态(静态多态)和运行时多态(动态多态)
1 静态多态
#include <iostream>
using namespace std;
class Animal
{
public:
void speak()
{
cout << "动物在说话" << endl;
}
};
class Cat :public Animal
{
public:
void speak()
{
cout << "小猫在说话" << endl;
}
};
void doSpeank(Animal &animal)
{
animal.speak();
}
int main()
{
Cat cat;
doSpeank(cat);
return 0;
}
输出:
动物在说话
说明:
静态多态地址在编译阶段绑定好
2 动态多态
运行时绑定地址
#include <iostream>
using namespace std;
class Animal
{
public:
virtual void speak()
{
cout << "动物在说话" << endl;
}
};
class Cat :public Animal
{
public:
virtual void speak()
{
cout << "小猫在说话" << endl;
}
};
void doSpeank(Animal &animal)
{
animal.speak();
}
int main()
{
Cat cat;
doSpeank(cat);
return 0;
}
输出:
小猫在说话
分析:
当父类中有了虚函数后,结构发生改变,内部多了一个虚函数表指针(virtual function pointer,vfptr)和一个虚函数表。通过vs2017的开发人员命令提示符可以查看
运行vs2017的开发人员命令提示符,cd到xx.cpp文件位置,输入cl /d1 reportSingleClassLayout类名 xx.cpp
查看
子类中发生了重写,替换了虚函数表中原有的speak(),即&Animal::speak 替换为 &Cat::speak
内部如何调用:
//父类的指针或引用指向子类对象
Animal *animal = new Cat();
animal->speak();
//animal->speak()执行效果与下面程序执行效果一样。
((void(*)()) (*(int *)*(int *)animal))();
在虚函数指针和虚函数表中都是int *类型
animal
地址
*(int *)animal
指向虚函数表
*(int *)*(int *)animal
函数地址
((void(*)()) (*(int *)*(int *)animal))
函数指针指向这个函数
((void(*)()) (*(int *)*(int *)animal))()
增加一个()调用