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.进程 ...
随机推荐
- 搭建docker swarm集群
环境介绍 管理节点 swarm01 192.168.5.140 工作节点 swarm02 192.168.5.141 管理节点执行 docker swarm init --advertise ...
- MASM32 - PlaySound的实现
MASM安装教程: https://blog.csdn.net/u010486308/article/details/105495848 代码参考: .model flat, stdcall opti ...
- kafka学习笔记01-kafka简介和架构介绍
一.kafka介绍 kafka 最开始是 Linkedin 用来处理海量的日志信息,后来 linkedin 于 2010 年贡献给了 Apache 基金会并成为了顶级项目. 后来开发 kafka 的一 ...
- CentOS7安装Chrome及驱动
目录 安装Chrome 更新Chrome 安装Chrome驱动程序 更新Chrome驱动程序 环境:CentOS Linux release 7.4.1708 (Core) 安装Chrome 下载安装 ...
- Vue 3 的 setup语法糖到底是什么东西?
前言 我们每天写vue3项目的时候都会使用setup语法糖,但是你有没有思考过下面几个问题.setup语法糖经过编译后是什么样子的?为什么在setup顶层定义的变量可以在template中可以直接使用 ...
- 案例分享:Qt国产麒麟系统某防“某显示控制项目”(多类设备自动化流程控制,数据分析整合与展示,定位图,深度图,热力图等,多应用协调管控,健壮容错)
喜报 我司承担的某防"某显示控制项目",已于近日顺利通过湖底验收. 需求 功能简介: 1.多类设备的显示.控制与管理 2.数据的分析与展示,定位图.深度图.热力图等 ...
- pinject依赖注入模块
pinject 是一个基于 Python 的轻量级依赖注入库,可以方便地实现依赖注入的功能. 下面我们将通过一个简单的示例来演示如何使用 pinject 实现依赖注入. 首先,我们需要安装 pinje ...
- 关于json序列化时报错json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
1.今天在写客户端与服务端交互的程序的时候,发现了一个问题 客户端代码 #客户端程序主要是发送注册请求/登录请求给服务端,服务端接收响应后回应对应的应答给客户端,客户端接收响应后,然后做一些操作 # ...
- day01---操作系统安装环境准备
虚拟机安装操作系统步骤 1.新建虚拟主机 2.选择自定义 3.稍后安装操作系统 4.操作系统选择linux 5.选择存放位置 6.cpu和核数选择,默认即可 7.内存分配 8.网络选择 9.控制器类型 ...
- ASP.NET Core 微信支付(二)【 发布到服务器上签名加密时报错:系统找不到指定的文件 APIV3】
参考资料 .Net微信支付退款操作"系统找不到指定的文件" 错误现象 微信支付(API v3)的统一下单接口和订单查询接口在本地调试成功,可以使用,但是发布到服务器上之后调用接口就 ...