【C++】多态虚表

news/2024/11/26 10:51:41/

多态——多种形态

多态的分类:

1.静态多态:函数重载和运算符重载(复用函数名)

2.动态多态:派生类和虚函数实现运行时多态

静态多态和动态多态的区别:

静态多态的函数地址早绑定——编译阶段确定函数地址

动态多态的函数地址晚绑定——运行阶段确定函数地址

另一种分类:

1.重载多态--函数重载&运算符重载

2.包含多态--virtual

3.强制多态--强制类型转换 _cast

4.参数多态--模板


地址早绑定和晚绑定

下面代码中父类:Animal,成员函数:speak,子类:Cat,成员函数:speak;

函数地址早绑定:

先使用父类的构造函数,输出animal speak。

class Animal
{
public:void speak(){ cout << "animal speak" << endl; }
};
class Cat :public Animal
{
public:void speak() { cout << "cat speak" << endl; }
};
void doSpeak(Animal &animal)
{animal.speak();
}
int main1()
{Cat cat;doSpeak(cat);//animal speak//父子之间允许类型转换,函数地址早绑定return 0;
}

函数地址晚绑定:

父类中使用虚函数,子类重写speak函数覆盖,输出cat speak。

实现动态多态:

1.有继承关系

2.子类要重写(函数返回值类型、名称、参数列表都相同)父类的虚函数

动态多态的使用:父类的 指针 或者 引用 执行子类对象!!!

子类将父类的虚函数表继承下来,如果子类重写了这个虚函数,则会将之前的虚函数覆盖,但父类自己的没有改变,当父类的指针或引用指向子类对象时,发生多态。

如果是基类同名同参的虚函数,则子类中可以不用写virtual。

class Animal
{
public:virtual void speak() { cout << "animal speak" << endl; }//加一个虚的关键字
};
class Cat :public Animal
{
public:void speak() { cout << "cat speak" << endl; }
};
void doSpeak(Animal &animal)
{animal.speak();
}
int main()
{Cat cat;doSpeak(cat);//cat speakreturn 0;
}

虚表

类中如果有虚函数,则会有一个(继承来的会有多个)vfptr虚函数指针。

如果是个空类,则大小为1个字节:占位。

在不算继承的情况下,如果里面只有虚函数(无论多少个),则为四个字节,一个指针的大小。指针指向一个虚表,虚表里面放着虚函数的入口地址。

class A
{
public:virtual void fa() { cout << "A::fa" << endl; }virtual void ga() { cout << "A::ga" << endl; }virtual void ha() { cout << "A::ha" << endl; }
private:int m_i;int m_j;
};
int main()
{A a;    
}

且其他成员地址都在虚表之后

可以把这个虚表看作是函数指针数组,可以定义一个函数指针指向这个数组,

int main()
{A a;typedef void (*Fun)();//函数指针Fun pf = NULL;pf = (Fun) * ((int*)*(int*)(&a));pf(); //A::fapf = (Fun) * ((int*)*(int*)(&a) + 1);pf();//A::fbpf = (Fun) * ((int*)*(int*)(&a) + 2);pf();//A::fc
}

类的地址第一个内容就是这个虚表地址:(int*)(&a),//如果不强转的话&a是a*类型的

fa的地址为虚表第一个元素(解引用):(int*)*(int*)(&a),

最后再解引用就是fa函数:*((int*)*(int*)(&a))

之后转成函数指针类型:(Fun)*((int*)*(int*)(&a))

就可以用函数指针调用虚函数了

虚表的个数

对于多继承,每个父类有自己的虚表。子类将新的虚函数放到第一个父类的虚表中。

下面A有一个虚指针,B有一个虚指针,C有一个虚指针,D继承了ABC的虚指针,并将自己独有的虚函数地址放在继承下来的A的虚表中

class A
{
public:virtual void fa() { cout << "A::fa" << endl; }virtual void ga() { cout << "A::ga" << endl; }
};
class B
{
public:virtual void fb() { cout << "B::fb" << endl; }virtual void gb() { cout << "B::gb" << endl; }
};
class C
{
public:virtual void fc() { cout << "C::fc" << endl; }virtual void gc() { cout << "C::gc" << endl; }
};
class D :public A, public B, public C
{
public:virtual void fd() { cout << "D::fd" << endl; }virtual void gd() { cout << "D::gd" << endl; }
};
void main()
{D d;cout << sizeof(D) << endl;//12,继承了三个虚指针,修改了第一个typedef void (*Fun)();Fun pf = (Fun) * ((int*)(*(int*)(&d)) + 1);pf();//A::gapf = (Fun) * ((int*)(*(int*)(&d)) + 2);pf();//D::fdpf = (Fun) * ((int*)(*(int*)(&d)) + 3);pf();//D::gd
}


http://www.ppmy.cn/news/29530.html

相关文章

JVM—类加载子系统

JVM细节版架构图 ​ 本文针对Class Loader SubSystem这一块展开讲解类加载子系统的工作流程 类加载子系统作用 1.类加载子系统负责从文件系统或者网络中加载class文件&#xff0c;class文件在文件开头有特定的文件标识即16进制CA FE BA BE&#xff1b; 2.加载后的Class类信息…

为什么FPGA在深度学习领域有着得天独厚的优势?

01 FPGA在深度学习领域有哪些优势 FPGA&#xff08;Field-Programmable Gate Array&#xff09;是一种灵活的可编程硬件设备&#xff0c;它在深度学习应用领域中具有许多优势。 首先&#xff0c;FPGA具有非常高的并行性。在深度学习中&#xff0c;许多计算都可以并行化&…

【机器学习】决策树(理论)

决策树&#xff08;理论&#xff09; 目录一、何为决策树1、决策树的组成2、决策树的构建二、熵1、熵的作用2、熵的定义3、熵的计算4、条件熵的引入5、条件熵的计算三、划分选择1、信息增益&#xff08; ID3 算法选用的评估标准&#xff09;2、信息增益率&#xff08; C4.5 算法…

后端程序员的前端基础-前端三剑客之HTML

文章目录1 HTML简介1.1 什么是HTML1.2 HTML能做什么1.3 HTML书写规范2 HTML基本标签2.1 结构标签2.2 排版标签2.3 块标签2.4 基本文字标签2.5 文本格式化标签2.6 标题标签2.7 列表标签(清单标签)2.8 图片标签2.9 链接标签2.10 表格标签3 HTML表单标签3.1 form元素常用属性3.2 i…

【微信小程序】-- 网络数据请求(十九)

&#x1f48c; 所属专栏&#xff1a;【微信小程序开发教程】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &…

119.(leaflet篇)文字碰撞

听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <!DOCTYPE html> <html>

K8s:Monokle Desktop 一个集Yaml资源编写、项目管理、集群管理的 K8s IDE

写在前面 Monokle Desktop 是 kubeshop 推出的一个开源的 K8s IDE相关项目还有 Monokle CLI 和 Monokle Cloud相比其他的工具&#xff0c;Monokle Desktop 功能较全面&#xff0c;涉及 k8s 管理的整个生命周期博文内容&#xff1a;Monokle Desktop 下载安装&#xff0c;项目管理…

Python每日一练(20230303)

1. 两数之和 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。 你可以按任意顺…