• 虚函数可不可以重载为内联 —— 在开启最大优化时gcc、clang和msvc的表现


    下面是对该问题的一种常见回答:

    首先,内联是程序员对编译器的一种建议,因此可以在在重载虚函数时在声明处加上inline关键字来修饰,
    但是因为虚函数在运行时通过虚函数表,而内联函数在编译时进行代码嵌入,因此在编译时编译器不接受虚函数变为内联函数的建议。

    如果你只是背八股,那么该问题到此为止。


    但是很明显,内联是对编译器的建议,cpp reference也没有规定是否应该内联重载了的虚函数(反正我是没找到,但如果有请告诉我出处,感谢!),因此这个问题又要根据具体编译器来分析了。

    测试代码:
    #include 
    
    class Base {
    public:
        void test() {
            int i = 10;
        	printf("Base::test<%p>\n", &i);
        }
    
        virtual void fun() {
            int i = 11;
            printf("Base::fun<%p>\n", &i);
        }
    };
    
    class Son: public Base{
    public:
        inline virtual void fun() override {
            int i = 12;
            printf("Son::fun<%p>\n", &i);
        }
    };
    
    int main()
    {
        Son son;
        Base base;
        Base * base_son = new Son;
    
    	// 最大优化下:
        // test()没有多态性,编译器判断可以内联
        son.test();        // 10
        base.test();       // 10
        base_son->test();  // 10
    
        son.fun();         // 12:没有表现出多态性,内联
        base.fun();        // 11:没有表现出多态性,内联
        base_son->fun();   // 12:表现出多态性,gcc和msvc没内联,clang内联了
        //! 不懂clang,似乎它在编译时能判断多态,不过想想也是,似乎是这里的多态代码过于简单了,
        //! Base * base_son = new Son; 这一句一看就知道base_son调用具有多态性的函数时调用的是子类的重载函数,
        //! 还可以使用更复杂的测试代码,我就懒得搞了,毕竟这个问题和编译器相关
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    在开启最大优化时,各编译器的表现(在Compiler Explorer网站测试):
    该测试并不严谨,只是菜鸡的随手一试罢了,有任何问题可以评论或私信来探讨。

    在gcc中:

    可以看到在开启最大优化时,虚函数是否重载为内联是取决于该虚函数是否在使用处表现出多态性,若有表现出多态性则不内联,否则内联之
    在这里插入图片描述

    在clang中:

    clang更聪明,它直接内联了展示出多态性的代码,不过似乎是这里的测试代码过于简单,使得多态性一眼丁真,需要多态性更复杂的代码来测试,但是我懒,也不懂clang
    在这里插入图片描述

    在msvc中:

    msvc在汇编代码中判断了重载的虚函数调用是否展现多态性,在图中的cmp rdx rax处,如果虚函数表第一项不是Son::fun则进行虚函数表中的函数调用,这明显就是展现了多态性进行的调用;如果没展现多态性,则执行下面的内联了的Son::fun,因此可以看出msvc的汇编代码既给出了Son::fun未内联的函数调用,也给出了Son::fun内联了的汇编代码
    在这里插入图片描述


    因此可以得出一个不是很严谨的结论:

    • 在未表现出多态性时,重载的虚函数会被编译器内联;
    • 在表现出多态性时,重载的虚函数不会被编译器内联,但是如果多态代码过于简单,clang则会内联;
  • 相关阅读:
    软件测试开发从0到1(自用,更新中)
    2022软考高项十大领域知识整理(四)-人力资源管理、干系人管理、采购管理
    jspm基于ssm的乐聘网人才招聘系统
    如何开发一款基于 Vite+Vue3 的在线表格系统(上)
    股票推荐系统,并查集
    前端培训丁鹿学堂:vue3的setup语法糖总结(二)
    被一个问题卡了近两天,下班后我哭了。。。
    k8s之volumes和volumeMounts
    [PHPMailer]PHP电子邮件教程
    小白备战大厂算法笔试(八)——搜索
  • 原文地址:https://blog.csdn.net/MYMarcoreus/article/details/134548807