• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

探索C++虚函数在g++中的实现(动多态)_虚函数表剖析

c# 搞代码 4年前 (2022-01-09) 21次浏览 已收录 0个评论
文章目录[隐藏]

探索C++虚函数在g++中的实现

本文是我在追查一个诡异core问题的过程中收获的一点心得,把公司项目相关的背景和特定条件去掉后,仅取其中通用的C++虚函数实现部分知识记录于此。

在开始之前,原谅我先借用一张图黑一下C++:

“无敌”的C++

如果你也在写C++,请一定小心…至少,你要先有所了解: 当你在写虚函数的时候,g++在写什么?

先写个例子

为了探索C++虚函数的实现,我们首先编写几个用来测试的类,代码如下:

C++

#include <iostream>using namespace std;class Base1{public:    virtual void f() {        cout << "Base1::f()" << endl;    }};class Base2{public:    virtual void g() {        cout << "Base2::g()" << endl;    }};class Derived : public Base1, public Base2{public:    virtual void f() {        cout << "Derived::f()" << endl;    }    virtual void g() {        cout << "Derived::g()" <&l<div>本文来源gaodai.ma#com搞##代!^码@网3</div>t; endl;    }    virtual void h() {        cout << "Derived::h()" << endl;    }};int main(int argc, char *argv[]){    Derived ins;    Base1 &b1 = ins;    Base2 &b2 = ins;    Derived &d = ins;    b1.f();    b2.g();    d.f();    d.g();    d.h();}

代码采用了多继承,是为了更多的分析出g++的实现本质,用UML简单的画一下继承关系:

示例代码UML图

代码的输出结果和预期的一致,C++实现了虚函数覆盖功能,代码输出如下:

Derived::f()Derived::g()Derived::f()Derived::g()Derived::h()

开始分析!

我写这篇文章的重点是尝试解释g++编译在底层是如何实现虚函数覆盖和动态绑定的,因此我假定你已经明白基本的虚函数概念以及虚函数表(vtbl)和虚函数表指针(vptr)的概念和在继承实现中所承担的作用,如果你还不清楚这些概念,建议你在继续阅读下面的分析前先补习一下相关知识,陈皓的 《C++虚函数表解析》 系列是一个不错的选择。

通过本文,我将尝试解答下面这三个问题:

  1. g++如何实现虚函数的动态绑定?

  2. vtbl在何时被创建?vptr又是在何时被初始化?

  3. 在Linux中运行的C++程序虚拟存储器中,vptr、vtbl存放在虚拟存储的什么位置?

首先是第一个问题:

g++如何实现虚函数的动态绑定?

这个问题乍看简单,大家都知道是通过vptr和vtbl实现的,那就让我们刨根问底的看一看,g++是如何利用vptr和vtbl实现的。

第一步,使用 -fdump-class-hierarchy 参数导出g++生成的类内存结构:

Vtable for Base1Base1::_ZTV5Base1: 3u entries0     (int (*)(...))04     (int (*)(...))(& _ZTI5Base1)8     Base1::fClass Base1   size=4 align=4   base size=4 base align=4Base1 (0xb6acb438) 0 nearly-empty    vptr=((& Base1::_ZTV5Base1) + 8u)Vtable for Base2Base2::_ZTV5Base2: 3u entries0     (int (*)(...))04     (int (*)(...))(& _ZTI5Base2)8     Base2::gClass Base2   size=4 align=4   base size=4 base align=4Base2 (0xb6acb474) 0 nearly-empty    vptr=((& Base2::_ZTV5Base2) + 8u)Vtable for DerivedDerived::_ZTV7Derived: 8u entries0     (int (*)(...))04     (int (*)(...))(& _ZTI7Derived)8     Derived::f12    Derived::g16    Derived::h20    (int (*)(...))-0x00000000424    (int (*)(...))(& _ZTI7Derived)28    Derived::_ZThn4_N7Derived1gEvClass Derived   size=8 align=4   base size=8 base align=4Derived (0xb6b12780) 0    vptr=((& Derived::_ZTV7Derived) + 8u)  Base1 (0xb6acb4b0) 0 nearly-empty      primary-for Derived (0xb6b12780)  Base2 (0xb6acb4ec) 4 nearly-empty      vptr=((& Derived::_ZTV7Derived) + 28u)

搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:探索C++虚函数在g++中的实现(动多态)_虚函数表剖析

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址