30.C++多态 3 (多态的原理,虚指针,虚函数表,抽象类)

devtools/2025/2/27 6:41:49/

⭐上篇文章:29.C++多态 2 (重载,重定义(隐藏),重写 三者的区别)-CSDN博客

⭐本篇代码:c++学习/17.C++三大特性-多态 · 橘子真甜/c++-learning-of-yzc - 码云 - 开源中国 (gitee.com)

⭐标⭐是比较重要的部分

目录

一. 抽象类

二. 多态的原理 ⭐⭐

2.1 计算带有虚函数的类大小

2.2 虚函数表指针与虚表

2.3 多态原理分析

三. 虚函数虚函数表的存放位置


一. 抽象类

        带有虚函数的类就是抽象类,抽象类无法实例化为对象。虚函数后面加上 = 0,这个函数就是纯虚函数

        纯虚函数的实现在子类中实现,以便完成多态

代码举例:

 下面A是一个纯虚函数,B继承A但是没有重写test,C重写了test

#include <iostream>
using namespace std;class A
{
public:virtual void test() = 0;	//纯虚函数在子类中实现
};class B : public A
{};class C : public A
{
public:virtual void test(){return;}};
int main()
{A a;B b;C c;
}

可以看到编译器不能生产 A 和 B的对象 

 这说明,如果抽象类的子类没有重写纯虚函数,这个类仍是抽象类

抽象类的作用:

        强制子类去重写虚函数

        世界上有很多事物是抽象的,需要抽象类去表示

二. 多态的原理 ⭐⭐

2.1 计算带有虚函数的类大小

分析一下,下面的输出是多少?

#include <iostream>
using namespace std;class A
{
public:virtual void test1() {}void test2() {}
private:int _a;
};int main()
{A a;cout << sizeof(a) << endl;return 0;
}

 分析类(结构体)的大小我们需要了解:

1 需要使用内存对齐规则。

2 类中的成员函数不占用空间。

可以看这篇文章:

5.C++面向对象2(类对象大小计算,结构体内存对齐,大小端存储方式,this指针)-CSDN博客

        上面的类A中,可以看到只有一个成员变量int占用4字节,最大对齐数 = min(4,8) = 4。所以

sizeof(A)应该是4字节。

 可事实是这样的吗?

        可以看到,输出的结果是8, 这里我们调试看一下

可以看到a中除了_a变量, 还有一个指针, 这个指针指向了函数test。

所以在32位系统下,int变量占4位,指针占4位。所以输出的结果是8.

如果换成64位,指针占8位。那么结果应该是16位

2.2 虚函数表指针与虚表

        在上面的测试中,可以看到对象a中有一个指针,这个指针是虚函数指针,本质是一个指针数组。

        虚函数指针指向了一张虚函数表(虚表),这个表中存放的是这个类的虚函数

增加更多的函数,并且一个类继承这个类进行观察。

测试代码如下:

#include <iostream>
using namespace std;class A
{
public:virtual void test1() {}virtual void test2() {}void test3() {}
private:int _a;
};class B : public A
{
public:virtual void test1() {}void test5() {}
private:int _b;
};int main()
{A a;B b;return 0;
}

调试查看的结果如下: 

 

         可以看到,这个虚函数指针指向的虚函数表中存放的都是虚函数的地址。

        如果子类重写了父类的虚函数,那么在子类的虚函数表中的这个重写的虚函数就会覆盖父类的虚函数

        如果子类没有重写父类的虚函数,那么在子类的虚函数表中的虚函数和父类的虚函数是一样的。

         派生类虚表生产的顺序为,1 拷贝一份父类的虚表 2 将重写的虚函数覆盖这个虚表 3 将增加的虚函数的地址写入虚表中(如果有的话)

2.3 多态原理分析

实现多态的两个条件:

1 完成对虚函数的重写

2 使用父类的指针或者引用去调用这个虚函数

        多态的原理是一种动态绑定。当我们的基类指针去调用相应对象的函数时候(这个时候是运行期间),会根据这个对象中的虚函数指针找到对应的虚表,再根据虚表中的相应函数地址去调用这个函数。最后完成多态

        满足多态以后的函数调用,不是在编译时确定的,是运行起来以后到 对象的中取找的。不满足多态的函数调用时编译时确认好的。

三. 虚函数虚函数表的存放位置

        1 虚函数是函数,存放再代码段

        2 虚函数表存放的是指针,是虚函数的地址。我们通过代码分析可以看到虚函数表其实也存放在代码段。

对于一个类对象 a 虚函数指针在第一个

&a 就是a的地址

(long long*)&a        就可以获取前8个字节,即虚函数指针的地址

*((long long*)&a)     对虚函数指针进行解引用就能找到虚表地址

测试代码如下:

#include <iostream>
using namespace std;class A
{
public:virtual void test1() {}
private:int _a;
};void f() {}int main()
{A a;int b;int* c = new int;const string d = "123";printf("虚函数表地址:%p\n", (void*)*(long long*)&a);printf("栈区地址:%p\n", &b);printf("堆区地址:%p\n", &c);printf("常量区地址:%p\n", &d);printf("代码区地址:%p\n", &f);return 0;
}

可以看到虚表的地址在代码段 

 


http://www.ppmy.cn/devtools/162988.html

相关文章

leetcode 73. 矩阵置零

题目如下 数据范围 如果一个点m(i,j) 0其中i j都大于0那么按照题目要求对应的m[0][j] m[i][0]都要赋值为0. 所以我们可以令第一行和第一列作为标记是否对应的列和行需要置为0. 又因为我们没法判断第一行和第一列所以需要额外两个变量标记第一列和第二列。 这样就可以满足题…

Lua的for循环中ipairs和pairs的区别

ipairs 主要用于便利连续的数字键,遍历table中遍历数组形式的表,下面是代码示例 local t {a 1,7, b 2, c 3,4,5,6} for k, v in ipairs(t) doprint(k, v) end输出的结果是: Pairs 主要用于遍历所有的键,包括非数字键,但是非数字键的顺序可能不同&#xff0c;下面是代码…

JavaScript系列(90)--前端脚手架开发

前端脚手架开发 &#x1f6e0;️ 前端脚手架是现代前端开发流程中的重要工具&#xff0c;它能够帮助开发者快速初始化项目结构、配置开发环境、设置构建流程&#xff0c;从而提高开发效率和标准化项目结构。本文将详细介绍前端脚手架的开发原理、实现方式以及最佳实践。 脚手…

给SQL server数据库表字段添加注释SQL,附修改、删除注释SQL及演示

目录 一. 前提小知识(数据库连接&#xff0c;数据库&#xff0c;SCHEMA&#xff0c;Table的关系) 二. 添加备注 2.1 添加备注基本语法(sys.sp_addextendedproperty) 2.2 SQL演示 2.3?fn_listextendedproperty函数查询备注个数 2.4 开发常用添加注释语法 三. 修改备注 …

鸿蒙开发中BindSheet应用 打造半模态转场效果

在鸿蒙开发中&#xff0c;BindSheet 组件可用于创建半模态窗口&#xff0c;通过设置合适的属性和添加动画效果&#xff0c;能够实现具有转场效果的半模态窗口。以下是详细的实现步骤和示例代码。 实现思路 布局设计&#xff1a;使用 BindSheet 组件创建半模态窗口&#xff0c…

2025最新智能优化算法:人工旅鼠算法(Artificial Lemming Algorithm, ALA)求解23个经典函数测试集,MATLAB

一、人工旅鼠优化算法 人工旅鼠算法&#xff08;Artificial Lemming Algorithm, ALA&#xff09;是2025年提出的一种新型生物启发式优化算法&#xff0c;受旅鼠的四种典型行为启发&#xff1a;长距离迁徙、挖洞、觅食和躲避捕食者。该算法通过模拟这些行为来解决复杂的优化问题…

P9231 [蓝桥杯 2023 省 A] 平方差--巧妙统计奇数的个数!

P9231 [蓝桥杯 2023 省 A] 平方差 题目 分析统计奇数个数统计4的倍数个数代码 题目 分析 看题目字挺少&#xff0c;条件&#xff0c;目的非常清晰&#xff0c;我脑子中的暴力算法直接涌现出来了^ ^&#xff0c;都是我看来一下L&#xff0c;R的范围QAQ 分享大佬题解 将x表示为…

嵌入式八股文(五)硬件电路篇

一、名词概念 1. 整流和逆变 &#xff08;1&#xff09;整流&#xff1a;整流是将交流电&#xff08;AC&#xff09;转变为直流电&#xff08;DC&#xff09;。常见的整流电路包括单向整流&#xff08;二极管&#xff09;、桥式整流等。 半波整流&#xff1a;只使用交流电的正…