• C++虚函数重载与虚表


    C++的类只要有一个虚函数,就会生成一张虚表

    class A
    {
    };
    
    class B
    {
    public:
    	virtual void vfunc1();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    sizeof(A) = 1	// 空类1个字节用于地址定位
    sizeof(B) = 4
    
    • 1
    • 2

    C++类虚表中函数顺序规则

    1. 从基类开始,按照申明顺序每遇到一个不是重写的虚函数,就记录在表中
    2. 如果有重载,则提前重载的虚函数
    3. 依次循环遍历子类,如果遇到重写,则替换相应的虚函数

    举例

    class A
    {
    public:
    	virtual void vfunc1() = 0;
    	virtual void vfunc2() = 0;
    	virtual void vfunc1(int x) = 0;
    	virtual void vfunc3() = 0;
    	virtual void vfunc1(int x, int y) = 0;
    };
    
    class B : public A
    {
    public:
    	virtual void vfunc1(int x) = 0;
    	virtual void vfunc4() = 0;
    	virtual void vfunc2(int x) = 0
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    请问B的虚表是应该是什么样的?

    1. 遍历A中的虚函数
    void A::vfunc1();
    
    • 1

    由于 vfunc1 有两个重载,按照第 2 条规则,依次提前重载函数

    void A::vfunc1();
    void A::vfunc1(int x);
    void A::vfunc1(int x, int y);
    
    • 1
    • 2
    • 3
    1. 继续遍历A中的虚函数
    void A::vfunc1();
    void A::vfunc1(int x);
    void A::vfunc1(int x, int y);
    void A::vfunc2();
    void A::vfunc3();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 由于 B 重写了 Avoid vfunc1(int x) 函数,所以将表中对应的函数替换
    void A::vfunc1();
    void B::vfunc1(int x);
    void A::vfunc1(int x, int y);
    void A::vfunc2();
    void A::vfunc3();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 添加 B::vfunc4() 到虚表中
    void A::vfunc1();
    void B::vfunc1(int x);
    void A::vfunc1(int x, int y);
    void A::vfunc2();
    void A::vfunc3();
    void B::vfunc4();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 由于 B::vfunc2(int x) 没有重写A中的函数,按照规则 1 添加到虚表中
    void A::vfunc1();
    void B::vfunc1(int x);
    void A::vfunc1(int x, int y);
    void A::vfunc2();
    void A::vfunc3();
    void B::vfunc4();
    void B::vfunc2(int x);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    搞清楚虚表有什么用?

    答:ABI兼容

    我们输出SDK时一般会这么写

    • awesome.h
    class IAwesomeSDK
    {
    public:
    	virtual void foo() = 0;
    	virtual void bar(int x) = 0;
    };
    
    extern "C" {
    
    // 创建SDK实例
    IAwesomeSDK *createAwesomeInstance();
    
    // 销毁SDK实例
    void destroyAwesomeInstance();
    
    } // extern "C"
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    别人使用时一般这么写

    • demo.cpp
    int main(int argc, char **argv)
    {
    	IAwesomeSDK *sdk = createAwesomeInstance();
    	sdk->foo();
    	sdk->bar();
    	destroyAwesomeInstance();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    未完待续…

  • 相关阅读:
    【性能测试】JMeter:集合点,同步定时器的应用实例!
    VS+Qt+C++ GDAL读取tif图像数据显示
    Mysql DATETIME与TIMESTAMP的区别
    Mycat高可用方案-HAProxy+Keepalived
    极狐GitLab CI 助力 .Net 项目研发效率和质量双提升
    LeetCode(cai鸟之路)139. 单词拆分
    Jenkins--基础--6.2--Pipeline--语法--声明式
    Elastic Connectors:增量同步对性能的影响
    C++模拟OpenGL库——图形学状态机接口封装(二):基于状态机接口的画线&画三角形
    小程序长文本限制显示行数
  • 原文地址:https://blog.csdn.net/u011134502/article/details/125551276