C++ 虚函数是正常调用还是虚拟调用?

标签 c++

假设一个虚函数在派生类对象上调用(通常在对象上或通过指针/引用),它覆盖了该函数,但它的派生类都没有覆盖它。它是通过 v 指针“虚拟地”调用还是作为普通函数调用以便所有优化/内联都适用于它?标准对此有任何说明吗?

class CBase{

public:
    virtual void doSomething() = 0;

};

class CDerived1 : public CBase{

public:
    void doSomething() override { /* do stuff */};

};

class CDerived2 : public CDerived1{


};

//...

CDerived1   derived1;
CDerived1*  p_derived1 = &derived1;

p_derived1->doSomething();

最佳答案

Does the standard say anything about this?

没有。调用是否使用动态调度机制是不可观察的行为。该标准只关注可观察到的行为。

有多少编译器“去虚拟化”虚拟调用最终是实现定义的。如果您只有 T t; 并且执行了 t.whatever(),那么您不应使用无法将其去虚拟化的编译器。

内联也会影响去虚拟化。鉴于 T t 声明,如果您向函数传递对此对象的引用,并且它采用 T& 参数,则如果该函数被内联,则可以将对它的调用去虚拟化。

但如果它是该函数的非内联实例(例如,指向该函数的指针,可能通过 std::function 或其他),那么去虚拟化就困难得多。你看,编译器看不到整个程序,所以它不能看你是否有某个类继承自 T 并覆盖了那个方法。

只有链接器,通过整个程序的优化,才有可能看到所有继承自它的类定义。即便如此……也许不会。因为 DLL/SO 从类继承在技术上仍然是可能的。并且非内联函数应该能够获取那些 T& 并调用它们的重写方法。

因此,一旦您离开内联链,其中对象的动态类型和对它的虚拟调用对编译器都是可见的,去虚拟化即使不是不可能,也会变得更加困难。

关于C++ 虚函数是正常调用还是虚拟调用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47344500/

相关文章:

c++ - 用于线程间通信的 volatile 和 mutex

c++ - 如何获得从资源文件生成的 Win32 对话框的视觉主题?

c++ - 访问 nullptr 怎么可能有效?

C# 窗体句柄属性

c++ - 通过 CRTP 的基类引用访问派生类的 constexpr 成员变量

c++ - 我可以使用 decltype() 或其他方法通过指针获取真实类型吗?

c++ - 按键事件处理

C++:结构 vector 的 vector 问题

c++ - Sprite 作为全局变量?

c++ - 是否可以在单线程应用程序中的多个 lua_State 之间共享一个表?