C++中虚表是什么
虚函数表,以及虚函数指针是实现多态性(Polymorphism)的关键机制。多态性允许我们通过基类的指针或引用来调用派生类的函数
定义
虚函数(Virtual Function)
定义:类中使用virtual 关键字修饰的函数 叫做虚函数
语法:
class Base {
public:
virtual void show() { cout << "Base show" << endl; }
};
虚函数表(Virtual Function Table)
- 定义:当类含有至少一个虚函数时,编译器会为该类创建一个虚函数表。这个表是一个编译时构建的静态数组,存储了指向类中所有虚函数的指针。如果一个派生类重写了这些函数,那么在派生类的虚表中,相应函数的指针会被更新为指向派生类中的版本。
- 作用:v-table使得在运行时可以实现函数的动态绑定,允许通过基类的指针或引用调用正确的函数版本。
虚函数指针(Virtual Pointer)
- 定义:每个含有虚函数的类的对象(实例化出的)会持有一个指向相应虚表的指针,这个指针通常被称为虚指针(vptr)。vptr是对象运行时的一部分,确保了当通过基类指针调用虚函数时,能够查找到正确的函数实现。
- 作用:在对象的生命周期开始时,构造函数会设置vptr以指向相应的虚函数表。如果有派生类对象,它的构造函数会更新vptr,以指向派生类的虚函数表。这保证了通过基类的引用或指针调用虚函数也会执行最派生类的重写版本。
示例
#include <iostream>
using namespace std;
class Base {
public:
virtual void func1() { cout << "Base::func1" << endl; }
virtual void func2() { cout << "Base::func2" << endl; }
};
class Derived : public Base {
public:
void func1() override { cout << "Derived::func1" << endl; }
// func2() 继承自 Base
};
void printVTable(void* obj) {
cout << "vptr Address: " << obj << endl;
void** vTable = *(void***)obj;
cout << "VTable[0] (func1): " << vTable[0] << endl;
cout << "VTable[1] (func2): " << vTable[1] << endl;
}
int main() {
Base* base = new Base();
Derived* derived = new Derived();
cout << "Base object:" << endl;
printVTable(base);
cout << "\nDerived object:" << endl;
printVTable(derived);
delete base;
delete derived;
return 0;
}
程序输出如下,可以看到没用重写的func2函数地址是一样的。
Base object:
vptr Address: 0x8c1510
VTable[0] (func1): 0x422270
VTable[1] (func2): 0x4222b0
Derived object:
vptr Address: 0x8c1530
VTable[0] (func1): 0x422330
VTable[1] (func2): 0x4222b0
如下图所示:

面试题
(来自2025腾讯实习面试)场景题:一个类 A,里面有一个打印 helloworld 的虚函数,然后类 A 会在构造函数里调用这个虚函数,此时有个类 B,继承A,重写了这个 helloworld虚函数,问你在创建类 B 时,会打印 A 里的 helloworld 还是 B 里的。
代码如下:
class A {
public:
A() {
print();
}
virtual void print() {
cout << "A print" << endl;
}
};
class B : public A {
public:
void print() override {
cout << "B print" << endl;
}
};
int main() {
A* aTemp = new B();
delete aTemp;
}
解答:基类构造函数执行的时候,派生类的部分尚未初始化,因此调用的虚函数不会下发到派生类中。
最终会打印 A print,而不是类 B 里重写的版本
C++中虚表是什么的更多相关文章
- 揭开C++类中虚表的“神秘面纱”
C++类中的虚表结构是C++对象模型中一个重要的知识点,这里咱们就来深入分析下虚表的在内存中的结构. C++一个类中有虚函数的话就会有一个虚表指针,其指向对应的虚表,一般一个类只会有一个虚表,每个虚表 ...
- C++反汇编第三讲,反汇编中识别虚表指针,以及指向的虚函数地址
C++反汇编第三讲,反汇编中识别虚表指针,以及指向的虚函数地址 讲解之前,了解下什么是虚函数,什么是虚表指针,了解下语法,(也算复习了) 开发知识为了不码字了,找了一篇介绍比较好的,这里我扣过来了,当 ...
- C++反汇编第二讲,反汇编中识别虚表指针,以及指向的虚函数地址
讲解之前,了解下什么是虚函数,什么是虚表指针,了解下语法,(也算复习了) 开发知识为了不码字了,找了一篇介绍比较好的,这里我扣过来了,当然也可以看原博客链接: http://blog.csdn.net ...
- C++中的初始化
C++中的RAII机制指明”对象创建时通过构造函数进行初始化,析构时通过析构函数释放资源”,但实际中因类无构造函数时编译器将自动合成一个默认构造函数,该构造函数只服务于自身编译器构造需要而不负责对象成 ...
- 逆向实用干货分享,Hook技术第二讲,之虚表HOOK
逆向实用干货分享,Hook技术第二讲,之虚表HOOK 正好昨天讲到认识C++中虚表指针,以及虚表位置在反汇编中的表达方式,这里就说一下我们的新技术,虚表HOOK 昨天的博客链接: http://www ...
- 初步学习C++中的继承关系
继承机制是面向对象程序设计使代码能够复用的最重要的手段,它同意程序猿在保持原有类特性的基础上进行扩展,添加功能. 这样产生新的类,称派生类.继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂 ...
- C++继承、多态与虚表
继承 继承的一般形式 子类继承父类,是全盘继承,将父类所有的东西都继承给子类,除了父类的生死,就是父类的构造和析构是不能继承的. 继承的访问权限从两方面看: 1.对象:对象只能直接访问类中公有方法和成 ...
- 图说C++对象模型:对象内存布局详解
0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局.虚表指针.虚基类指针等有深入了解的朋友可以慢慢看. 本文的结论都在VS2013上得到验证.不同的编译器在内存布局的细节上可能有 ...
- C++STL - 模板的其他特性
之前已经总结过函数模板和类模板了,对于模板还有一些其他的特性,这篇主要介绍这些特性.主要都是一些特殊情况. 模板的其他特性 1.缺省参数 (1)类模板的模板参数可以带有缺省值,实例化该模板时,如果提供 ...
- C/C++ 笔试题
/////转自http://blog.csdn.net/suxinpingtao51/article/details/8015147#userconsent# 微软亚洲技术中心的面试题!!! 1.进程 ...
随机推荐
- Postgresql-数据库无法停止,报错:pg_ctl server does not shut down
根据您的查询,pg_ctl server does not shut down(pg_ctl服务无法关闭)的原因可能有很多.以下是一些可能的解决方案和代码示例: (1)杀死所有与PostgreSQL相 ...
- mysql5.7 大量sleep连接解决方法
show processlist 查看发现有大量sleep进程 查看当前数据库设置的最大连接数 show variables like 'max_connections'; 如果是生产环境需要紧急处理 ...
- NC21125 践踏
题目链接 题目 题目描述 首先给定一个定值k,支持如下操作(在数轴上) 加入一条线段[l,r] 删除一条已经存在的线段 给定x,问有多少个区间包含x+kt,其中t是一个整数变量,即t ∈ Z 比如说当 ...
- Java集合篇之set,面试官:请说一说HashSet、LinkedHashSet、TreeSet的区别?
写在开头 Java的集合世界中主要由List,Set,Queue,Map构成,我们在之前的博文中已经学习了List,接下来我们继续学习Set集合. Set特点:存取无序,不可以存放重复的元素,不可以用 ...
- Rancher 2.x 安装
Rancher 是一个容器管理平台.Rancher 简化了使用 Kubernetes 的流程. 下面记录一下手动安装Rancher的步骤 1. 部署 Rancher Server 执行以下命令即可( ...
- 虚拟机ubuntu配置静态IP
手头搭建了几天虚拟机ubuntu用来做微服务环境的搭建,目前使用的是DHCP分配的网络,每次启动各台服务器的ip都是随机的 管理起来有点乱,所以就要把他们配置成静态的ip.具体操作步骤如下: 我直接用 ...
- jenkins构建第一个maven项目
1. 项目介绍 spring boot样例github项目. 大家可以访问:https://github.com/mudfish/springbootdemo 2. jenkins中新建maven任务 ...
- 获取Linux mac地址(centos与ubuntu通用)
ip -a addr| grep link/ether | awk '{print $2}'| head -n 1 获取Linux mac地址(centos与ubuntu通用)
- Python2升级到Python3
操作系统环境:CentOS Linux release 7.4.1708 (Core). 系统默认Python版本为2.7. 升级前的版本信息: [root@cch-spider-web1 ~]# l ...
- 案例分享:Qt出版社书籍配套U盘资源播放器软件定制(脚本关联播放器与资源文件,播放器,兼容win7,win10和mac)
红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术.树莓派.三维.OpenCV.OpenGL.ffmpeg.OSG.单片机.软硬结合等等)持续更新中-(点击传送门) 合作案例专栏:案例分享(体 ...