虚函数、静态绑定和动态绑定

news/2024/11/17 2:27:08/

静态绑定

class Base
{
public:Base(int data) :ma(data) {}void show() { cout << "Base::show()" << endl; }void show(int) { cout << "Base::show(int)" << endl; }protected:int ma;
};class Derive : public Base
{
public:Derive(int data = 20) : Base(data), mb(data) {}void show() { cout << "Derive::show()" << endl; }
private:int mb;
};int main()
{Derive d(50);Base* pb = &d;// 都是 调用基类的成员函数pb->show(); // 静态绑定,编译时期类型Basepb->show(10);cout << sizeof(Base) << endl; //4cout << sizeof(Derive) << endl;//8cout << typeid(pb).name() << endl; // class Base*cout << typeid(*pb).name() << endl; // class Basereturn 0;
}

虚函数

一个类添加了虚函数,对这个类有什么影响?

  1. 如果类里定义了虚函数,那么编译阶段,编译器给这个类产生一个唯一的vftable虚函数表,主要存储的内容就是RTTI(Runtime Type Identification)指针和虚函数地址。程序运行时,每张虚函数表都会加载到内存的.rodata
  2. 一个类里面定义了虚函数,那么定义该类对象时,程序运行时,内存中开始部分,多存储一个虚函数表指针(虚函数表指针放在类存储的最前面4个字节),指向相应类型的虚函数表vftable.
  3. 一个类型定义个n个对象,它们都要各自的vfptr,指向的是同一张虚函数表
  4. 虚函数表编译时生成,运行时放到只读数据段(.rodata
  5. 一个类里虚函数个数,不影响内存大小(都只是存一个vfptr),影响的只是虚函数表大小

在这里插入图片描述

其中&RTTI下面的0表示RTTI指针在整个对象内存空间的偏移量

如果派生类中的方法,和基类继承来的方法,返回值、函数名、参数列表都相同,而且基类方法是virtual,那么派生类的这个方法,自动处理成虚函数,完成了重写(或称为覆盖)

class Derive : public Base
{
public:Derive(int data = 20) :Base(data), mb(data) {}void show() { cout << "Derive::show()" << endl; }
private:int mb;
};

子类对象虚函数表如下图

在这里插入图片描述

静态绑定时,汇编直接就是调用具体函数

在这里插入图片描述

如果是动态绑定,则汇编不会call具体的函数而是虚函数表中的虚函数地址,部分汇编指令

在这里插入图片描述

Derive d(50);
Base* pb = &d;
pb->show(); // 检测到函数是虚函数,动态绑定,调用Derive::show()
pb->show(10);cout << sizeof(Base) << endl; // 8 (多了vfptr)
cout << sizeof(Derive) << endl; // 12cout << typeid(pb).name() << endl; // class Base *
cout << typeid(*pb).name() << endl; // class

pb的类型如何确定?

Base无虚函数,*pb识别的就是编译期类型即Base

如果Base有虚函数,就要去其对应虚函数表中查RTTI指针,得出运行时的类型

可以通过visual studio–》【工具】–》【命令行】查看类的对象模型

cl extend01.cpp /d1reportSingleClassLayoutDerive

在这里插入图片描述

基类的对象模型如下

在这里插入图片描述

只要基类有虚函数,派生类是否重写虚函数都会生成vfptrvftable(同一个类的所有对象只有一张表),基类有虚函数时,虚表指针是从基类带来的

要点

  • 虚函数的调用不一定是动态绑定

如,在类的构造函数中调用虚函数也是静态绑定,因为对象未建立,虚函数表还没生成。

  • 对象本身调用虚函数是静态绑定,只有用指针引用指向一个对象来进行调用虚函数才可能发生动态绑定.

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

相关文章

【LeetCode】9,回文数。 难度等级:简单。巧妙解法很多,值得推敲。

文章目录 一、题目二、我的解答&#xff1a;逐个判断对应位置的首末数字是否相同三、其他解答3.1 将数字x转为字符串进行处理3.2 反转一半数字进行比较 LeetCode 第9题&#xff0c;回文数&#xff1b;难度等级&#xff1a;简单 一、题目 二、我的解答&#xff1a;逐个判断对应…

【网络进阶】WebSocket协议

文章目录 1. Web实时技术的应用2. WebSocket协议介绍2.1 WebSocket的工作原理2.2 优点2.3. 使用场景2.4 实现细节 3. WebSocket服务器实现3.1 客户端代码&#xff08;HTML & JavaScript&#xff09;3.2 服务器端代码&#xff08;C&#xff09;3.3 测试结果 1. Web实时技术的…

CypherRat使用

cypherrat3.5 安卓远控&#xff0c;很早之前在tg下的&#xff0c;现在可能有高版本的 使用感受 图形化界面&#xff08;相比于msf&#xff09;可用于演练新场景&#xff0c;实战的话只能用xx破解版或是瑟瑟apk让人忽视风险继续安装由于国内安卓&#xff0c;部分功能失效 生成…

五种最危险的新兴网络攻击技术

SANS研究所的网络专家揭示了包括网络罪犯和民族国家行为者在内的网络攻击者正在使用的五种最危险的新兴网络攻击技术。在旧金山举行的RSA网络安全会议上&#xff0c;由SANS研究所的几位分析师组成的讨论组讨论了新兴的网络攻击战术、技术和程序&#xff0c;并提供了如何为企业做…

Python 面向对象

Python 是一种面向对象编程语言&#xff0c;支持类、对象、继承、多态等面向对象特性。下面是一些 Python 面向对象编程的基本概念和操作&#xff1a; 1. 定义类和对象 在 Python 中&#xff0c;可以使用 class 关键字定义类。类包含属性和方法&#xff0c;属性是类的数据成员…

界面控件DevExpress WPF富文本编辑器,让系统拥有Word功能(二)

DevExpress WPF控件的富文本编辑器允许开发者将文字处理功能集成到下一个WPF项目中&#xff0c;凭借其全面的文本格式选项、邮件合并以及丰富的终端用户选项集合&#xff0c;可以轻松地提供Microsoft Word功能。 DevExpress WPF拥有120个控件和库&#xff0c;将帮助您交付满足…

AMBA协议-AXI协议详解(读写时序、Outstanding、乱序传输、原子操作)

目录 1. AXI 写通道信号 1.1. 写地址通道信号 1.2. 写数据通道信号 1.3. 写response通道信号 1.5. 握手规则 1.4. AXI 写通道之间关系 2. AXI 读通道信号 2.1. 读地址通道信号 2.2. 读数据通道信号 2.3. AXI 读通道之间关系 3. AXI传输 3.1. AXI突发读传输 3.2. …

2022 gdcpc题解(10/13)

2022gdcpc 和学弟vp了一下这场&#xff0c;本来抓的数学选手咕咕了&#xff0c;只有2个人&#xff0c;打下来的感觉就是套路题和码量太大了&#xff0c;太久没写码量题导致 I I I调太久了&#xff0c;最后G没写完&#xff0c;K也没冲出来&#xff0c;感觉数学大爹在的话这K应该…