可以将在基类中未内联的纯虚方法内联为子类

Can subclass inline a pure virtual method that is not inline in the base?

本文关键字:方法 子类 基类      更新时间:2023-10-16

据我所知,编译器可以在编译时知道对象在运行时的类型(c++ faq)时内联虚函数调用。

但是,当从基类实现纯虚方法时会发生什么?同样的规则也适用吗?下面的函数调用是内联的吗?

class base
{
public:
    virtual void print() = 0;
    virtual void callPrint()
    {
        print(); // will this be inline?
    }
};
class child : public base
{
public:
    void print() { cout << "hellon"; }
};
int main()
{
    child c;
    c.callPrint();
    return 0;
}
编辑:

我认为我原来的示例代码实际上是我想问的问题的一个糟糕的表示。我已经更新了代码,但问题仍然是一样的。

编译器从未被要求内联函数调用。在这种情况下,允许内联函数调用,因为它知道c的具体类型(因为它不是通过指针或引用间接的,编译器可以看到它被分配为child的位置)。因此,编译器知道使用的是print()的哪个实现,可以选择不间接执行vtable,进一步选择内联函数的实现。

然而,编译器也可以自由地而不是内联它;如果它决定这样做,它可能插入对child::print()的直接调用,或者间接地通过虚函数表插入。 这些优化通常归结为"as-if"规则——编译器必须表现得就好像在间接执行一个完整的虚变量表——这意味着结果必须是相同的,但是如果结果相同,编译器可以选择不同的方法来实现结果。这包括内联等

答案当然是"视情况而定",但原则上没有优化的障碍。事实上,你甚至没有在这里做任何多态,所以这真的很直接。

如果你有这样的代码,这个问题会更有趣:

child c;
base & b = c;
b.print();

关键是编译器此时知道动态分派的最终目标是什么(即child::print()),因此可以进行优化。(当然,有两个单独的优化机会:一个是避免动态分派,另一个是使目标函数体在TU中可见。)

您只需要注意以下几条规则:

1)编译器永远不会被强制内联——即使使用指令或在头文件中定义方法。

2)多态性必须总是有效的。这意味着当存在动态调用的可能性时,编译器将更倾向于通过vftable调用函数,而不是将其内联。