静态多态和动态多态的区别就是函数地址是早绑定(静态联编)还是晚绑定(动态联编)。如果函数的调用,在编译阶段就可以确定函数的调用地址,并产生代码,就是静态多态(编译时多态),就是说地址是早绑定的。而如果函数的调用地址不能编译不能在编译期间确定,而需要在运行时才能决定,这这就属于晚绑定(动态多态,运行时多态)。
静态联编
地址早绑定 编译阶段绑定好地址
动态联编
地址晚绑定 ,运行时候绑定好地址
多态
父类的引用或指针指向子类对象
多态原理解析
当父类中有了虚函数后,内部结构就发生了改变
内部多了一个 vfprt
virtual function pointer 虚函数表指针
指向 vftable 虚函数表
父类中结构 vfptr &Animal::speak
子类中 进行继承 会继承 vfptr vftable
构造函数中 会将虚函数表指针 指向自己的虚函数表
如果发生了重写,会替换掉虚函数表中的原有的speak,改为 &Cat::speak
深入剖析,内部到底如何调用
((void(*)()) (*(int*)*(int*)animal))();
猫吃鱼的函数调用(编译器的调用)
多态的成立条件:
有继承
子类重写父类虚函数函数
a) 返回值,函数名字,函数参数,必须和父类完全一致(析构函数除外)
b) 子类中virtual关键字可写可不写,建议写
类型兼容,父类指针,父类引用 指向 子类对象
main.cpp
// 41.多态.cpp : 定义控制台应用程序的入口点。
//
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class Animal
{
public:
virtual void speak()
{
cout << "动物在说话" << endl;
}
virtual void eat()
{
cout << "动物在吃饭" << endl;
}
};
class Cat :public Animal
{
public:
void speak()
{
cout << "小猫在说话" << endl;
}
virtual void eat()
{
cout << "小猫在吃鱼" << endl;
}
};
//调用doSpeak ,speak函数的地址早就绑定好了,早绑定,静态联编,编译阶段就确定好了地址
//如果想调用猫的speak,不能提前绑定好函数的地址了,所以需要在运行时候再去确定函数地址
//动态联编,写法 doSpeak方法改为虚函数,在父类上声明虚函数,发生了多态
// 父类的引用或者指针 指向 子类对象
void doSpeak(Animal & animal) //Animal & animal = cat
{
animal.speak();
}
//如果发生了继承的关系,编译器允许进行类型转换
void test01()
{
Cat cat;
doSpeak(cat);//class Animal的speak没有定义成虚函数的时候输出:动物在说话
//class Animal的speak有定义成虚函数virtual的时候输出:小猫在说话
}
void test02()
{
cout << "sizeof(Animal)====" << sizeof(Animal) << endl;
//sizeof(Animal)====4
//父类指针指向子类对象 多态
Animal * animal = new Cat;
animal->speak();//输出:小猫仔说话
// *(int*)*(int*)animal 函数地址
((void(*)()) (*(int*)*(int*)animal))();//最后的()是调用speak方法,输出:小猫仔说话
// *((int*)*(int*)animal+1)猫吃鱼的地址
((void(*)()) (*((int*)*(int*)animal + 1)))();//最后的()是调用eat方法输出:小猫在吃鱼
}
int main(){
//test01();
test02();
system("pause");
return EXIT_SUCCESS;
}
EXE2:
//抽象制作饮品
class AbstractDrinking{
public:
//烧水
virtual void Boil() = 0;
//冲泡
virtual void Brew() = 0;
//倒入杯中
virtual void PourInCup() = 0;
//加入辅料
virtual void PutSomething() = 0;
//规定流程
void MakeDrink(){
Boil();
Brew();
PourInCup();
PutSomething();
}
};
//制作咖啡
class Coffee : public AbstractDrinking{
public:
//烧水
virtual void Boil(){
cout << "煮农夫山泉!" << endl;
}
//冲泡
virtual void Brew(){
cout << "冲泡咖啡!" << endl;
}
//倒入杯中
virtual void PourInCup(){
cout << "将咖啡倒入杯中!" << endl;
}
//加入辅料
virtual void PutSomething(){
cout << "加入牛奶!" << endl;
}
};
//制作茶水
class Tea : public AbstractDrinking{
public:
//烧水
virtual void Boil(){
cout << "煮自来水!" << endl;
}
//冲泡
virtual void Brew(){
cout << "冲泡茶叶!" << endl;
}
//倒入杯中
virtual void PourInCup(){
cout << "将茶水倒入杯中!" << endl;
}
//加入辅料
virtual void PutSomething(){
cout << "加入食盐!" << endl;
}
};
//业务函数
void DoBussiness(AbstractDrinking* drink){
drink->MakeDrink();
delete drink;
}
void test(){
DoBussiness(new Coffee);
cout << "--------------" << endl;
DoBussiness(new Tea);
}
本文深入探讨了静态多态与动态多态的区别,重点讲解了函数地址的早绑定与晚绑定机制。通过实例演示了虚函数表的概念,以及如何在运行时确定函数调用,实现了动态联编。此外,文章还提供了C++代码示例,展示了多态的实现过程。

被折叠的 条评论
为什么被折叠?



