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

时间:2017-11-17 06:24:57

标签: 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();

1 个答案:

答案 0 :(得分:4)

  

标准是否对此有所说明?

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

多少编译器" devirtualize"虚拟调用最终是实现定义的。如果您只有T t;并且t.whatever(),那么您就不应该使用无法虚拟化的编译器。

内联也会影响虚拟化。给定T t声明,如果您传递一个函数对该对象的引用,并且它需要一个T&参数,那么如果该函数被内联,则可以对其进行半虚拟化。

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

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

因此,一旦你留下一个内联链,其中对象的动态类型和虚拟调用对编译器都是可见的,那么即使不是不可能,虚拟化也会变得更加困难。