据我了解,编译器可以在编译时知道对象的类型在运行时(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 << "hello\n"; }
};
int main()
{
child c;
c.callPrint();
return 0;
}
修改
我认为我原来的示例代码实际上是我想要问的不好的代表。我已经更新了代码,但问题仍然存在。
答案 0 :(得分:10)
编译器永远不需要 来内联函数调用。在这种情况下,允许内联函数调用,因为它知道c
的具体类型(因为它不通过指针或引用间接,编译器可以看到它在哪里被分配为child
)。因此,编译器知道使用了print()
的哪个实现,并且可以选择不执行vtable间接,并进一步选择内联函数的实现。
但是,编译器也可以不内联它;它可能会直接调用child::print()
,或者通过vtable直接调用,如果它决定这样做的话。
这些优化通常可归结为“as-if”规则 - 编译器必须按 as 进行完全vtable间接操作 - 这意味着结果必须相同,但如果结果相同,编译器可以选择不同的方法来实现结果。这包括内联等。
答案 1 :(得分:3)
答案当然是&#34;它取决于&#34;,但原则上没有阻碍优化。事实上,你在这里甚至没有做任何多态的事情,所以这真的是直截了当的。
如果你有这样的代码,问题会更有趣:
child c;
base & b = c;
b.print();
关键是编译器在这一点上知道动态调度的最终目标是什么(namly child::print()
),因此这有资格进行优化。 (当然,有两个独立的优化机会:一个是通过避免动态调度,一个来自目标的功能体在TU中可见。)
答案 2 :(得分:1)
您应该注意几条规则:
1)编译器永远不会被强制内联 - 甚至使用指令或在头文件中定义方法。
2)多态性必须始终有效。这意味着编译器更愿意通过vftable调用函数,而不是在存在动态调用的可能性时内联函数。