惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
小众软件
小众软件
博客园_首页
博客园 - 聂微东
V
V2EX
WordPress大学
WordPress大学
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
罗磊的独立博客
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 司徒正美
博客园 - 三生石上(FineUI控件)
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
S
SegmentFault 最新的问题
J
Java Code Geeks
Last Week in AI
Last Week in AI
The Cloudflare Blog
月光博客
月光博客
雷峰网
雷峰网
宝玉的分享
宝玉的分享
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Hugging Face - Blog
Hugging Face - Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
有赞技术团队
有赞技术团队
人人都是产品经理
人人都是产品经理
博客园 - Franky
腾讯CDC
Jina AI
Jina AI
博客园 - 叶小钗
大猫的无限游戏
大猫的无限游戏
阮一峰的网络日志
阮一峰的网络日志
量子位
爱范儿
爱范儿
美团技术团队
T
Tailwind CSS Blog
博客园 - 【当耐特】
D
Docker
IT之家
IT之家
V
Visual Studio Blog
P
Proofpoint News Feed
L
LangChain Blog
Engineering at Meta
Engineering at Meta
C
Check Point Blog
G
Google Developers Blog
Google DeepMind News
Google DeepMind News
云风的 BLOG
云风的 BLOG
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Azure Blog
Microsoft Azure Blog
B
Blog RSS Feed
Recorded Future
Recorded Future

博客园 - 新西兰程序员

C++ 构造函数中的初始化参数列表initializer list C++中的线程thread,以及C++11中的std::atomic学习 Leetcode56 Merge Intervals 合并区间 -- C++实现 C++中的内存对齐 C++中的static关键字使用以及全局变量 C++17中的结构化绑定Structured Binding C++中的函数参数是指针类型, 是按值传递 C++中异常处理机制中的栈展开stack unwinding C++实现链表反转 Linux中的性能分析工具 perf 来分析C++性能 C++17中新建一个类时,编译器默认生成的类成员函数 QT中的元对象系统 Leetcode 114 - 二叉树展开为链表 Leetcode65 有效数字 - 判断给定的字符串是否是一个有效数字 LettCode2289-Steps to Make Array Non-descreasing C#中的委托详解 C++中的std::function C++中的仿函数Functor C++中的const和constexpr异同比较 C++中的左值和右值,以及右值引用,移动语义 C++中传递参数是指针类型以及传入参数是指针的指针(**)详解 C++中GetTickCount函数学习 C++中以类的成员函数作为Windows callback函数需要设置成static函数 C#中的System.Security.SecureString学习 C++中的悬挂指针和野指针 C++中四种不同的对象生存方式(in stack, in heap, global, local static) C#中使用Parallel类来进行多线程并发编程 String类型转LPCTSTR -----理解C++中的字符串类型转换 C++中基类指针指向派生类对象 数据结构 - 栈的学习
C++中的虚函数和虚函数表
新西兰程序员 · 2024-04-03 · via 博客园 - 新西兰程序员

在上面一篇博客中  https://www.cnblogs.com/wphl-27/p/18111083,提到了虚函数,纯虚函数

这篇博客我想继续进一步来说一下虚函数和虚函数表

在C++中,每一个含有虚函数的类,编译器都会为它啊做出一个虚函数表(通常叫做 vtable), 这个虚函数表里面的每个元素都是函数指针,每个元素(函数指针)指向一个虚函数的地址.

除此之外,编译器还会为这种含有虚函数的类,添加上一个成员变量,这个成员变量是一个指向它的虚函数表的指针(通常称为 vptr). 我们来看下面这个例子

class Class1  {
public :
    data1;
    data2;
    memfunc();
    virtual vfunc1();
    virtual vfunc2();
    virtual vfunc3();
};

这个Class1 ,它里面包括3个虚函数,我们来看看这个类在内存中空间

我们可以看到,它自动增加了一个成员变量 vptr, 这是一个指针,可以看到它指向的是Class1的虚函数表vtable, 这个虚函数表中有3个元素,是3个函数指针,它们分别指向Class1的三个虚函数的地址

当有一个派生类来继承基类Class1时,它会继承基类的虚函数表(以及其他所有可以继承的成员),  派生类中同样有这个新增的成员变量 vptr, 它同样指向派生类的虚函数表.

当我们在派生类中改写某个虚函数时,它继承下来的虚函数表就受了影响,虚函数表中对应的这个虚函数的函数指针,指向的地址将不再是基类的函数地址,而是改写后的派生类中该虚函数的函数地址

我们来看个例子:

class Class2 : public Class1 {
public :
    data3;
    memfunc();
    virtual vfunc2();
};

它的内存空间是这样的

可以看到Class2的虚函数表vtable中,它的第二个函数指针指向的是Class2::vfunc2(), 而不再是基类的Class1::vfunc1(), 也就是说它存的是Class2函数自己的重写后的vfun2函数的地址

所以一个「指向Class1所生对象」的指针,所调用的 vfunc2 就是 Class1::vfunc2,而一个「指向Class2 所生对象」的指针,所调用的 vfunc2 就是 Class2::vfunc2。

这也就是说我们在上篇博客 

C++中基类指针指向派生类对象  中提到的动态联编机制。 动态联编,在运行时,而不是编译时,会根据虚函数表,来做出正确的选择