假设在派生类对象(通常在对象上或通过指针/引用)上调用虚函数,该函数覆盖该函数但其派生类都不会覆盖它。它被称为"虚拟"通过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();
答案 0 :(得分:4)
标准是否对此有所说明?
没有。调用是否使用动态调度机制是不可观察的行为。标准只关注可观察的行为。
多少编译器" devirtualize"虚拟调用最终是实现定义的。如果您只有T t;
并且t.whatever()
,那么您就不应该使用无法虚拟化的编译器。
内联也会影响虚拟化。给定T t
声明,如果您传递一个函数对该对象的引用,并且它需要一个T&
参数,那么如果该函数被内联,则可以对其进行半虚拟化。
但是如果它是该函数的非内联实例(例如,指向函数的指针,可能通过std::function
或其他),那么虚拟化就更难了。看,编译器没有看到整个程序,所以它不能看看你是否有一个继承自T
的某个类并重写该方法。
只有链接器通过整个程序优化才能看到从中继承的所有类定义。即便如此......也许不是。因为DLL / SO在技术上仍然可以从类继承。并且非内联函数应该能够接受那些T&
并调用它们被重写的方法。
因此,一旦你留下一个内联链,其中对象的动态类型和虚拟调用对编译器都是可见的,那么即使不是不可能,虚拟化也会变得更加困难。