虚函数在c++中总是不能内联吗?

Is it always true that virtual function cannot be inlined in C++?

本文关键字:不能 函数 c++      更新时间:2023-10-16

据说虚函数不能内联。如果一个函数被声明为虚函数,它就不能在代码中的任何地方内联,或者它只在某些情况下适用吗?(如。(从基指针调用方法与从引用调用方法,等等)

不,虚函数确实可以内联。虚拟调度仅在多态调用虚拟方法时使用(即,在指针或对象引用上)。但是,当在对象上调用虚方法时,不使用虚分派,编译器可以自由地内联它认为合适的方法

给定:

struct T {
   virtual void foo() { /* something */ }
};

使用多态性 (如果您通过pointer-to-Treference-to-T调用foo() )

T* ptr = get_ptr_somehow();
ptr->foo();

如果编译器知道 T是其继承树中的唯一节点,它可以放弃虚拟调用并可能内联函数。然而,这是一个非常不可能的场景,我怀疑它是否能被探测到。在所有其他情况下,由于运行时调度,内联是不实际的。

静态调度 (如果你在一个bog标准对象上调用foo() )

T obj;
obj.foo();

在这种情况下,编译器知道obj的动态类型是T,因此它不需要虚拟分派,因此如果它愿意,可以内联函数代码。

T* ptr = get_ptr_somehow();
ptr->T::foo();

在这种情况下,编译器不知道obj的动态类型,但它知道它将调用哪个函数,知道它不需要虚拟分派,因此可以内联函数代码,如果它想。

虚成员函数基本上是一个指向函数的指针,该指针根据类层次结构实现指向要调用的正确函数。(注意,它不一定是一个指针,但它经常这样实现,因为它似乎是这个抽象的最有效的实现)。

这表明只在运行时确定将调用哪个函数。

那么如何内联一个只在运行时知道的函数呢?不可能。

除非你有一个JIT编译器:)the_drow

正确的。这是不常见的,您可能会在启动时损失一些性能,但仍然是正确的。

例如,在堆栈上或类内部声明的对象不需要对其被调用的虚函数进行动态分派,因为编译器知道堆栈上所有对象的类型,所以基本上是任何值。虚函数调度只能通过指针或引用进行。

当涉及到优化时,很少是正确的。一般来说,如果编译器无法判断对象的实际类型,则必须在运行时解析虚函数。如果你有一个实际的实例(Class vs . Class&),那么编译器可以确定。如果你有一个参考,它将不得不猜测;如果调用函数本身是内联的,它可能会以这种方式标识静态类型,也可能不会。

注意,在这种情况下,指针和引用之间没有区别。在任何一种情况下,都可以获得运行时多态性。

虚函数(方法)可以内联。请记住,inline关键字是对编译器的建议,而不是要求。

内联代码很像将函数原样粘贴到可执行文件中需要的地方。没有创建独立的函数。

当存在指向内联函数的指针(由编译器在内部或由程序员在外部)时,可以不使用内联。当有指向内联函数的指针时,必须有一个内联函数实例。编译器可以自由地内联代码,但必须在静态(固定)位置有一个实例来满足指针。

我的建议是内联简单的,少于5行代码,不使用分析器的方法。记住,内联通常是将代码放在头文件中。当方法的代码被更改时,依赖于头文件的所有翻译单元都必须重新构建。这在大型系统中可能代价高昂。一般来说,大块的代码只应该在之后内联,它们被验证,并且只是为了提高性能分析器规定的效率。