C++ 虚函数不能内联到C++;?

C++ 虚函数不能内联到C++;?,c++,optimization,compiler-construction,C++,Optimization,Compiler Construction,据说虚拟函数不能内联。如果一个函数被声明为虚函数,它就不能在代码中的任何地方内联,或者它只在某些情况下适用,这是真的吗?(例如,从基指针调用方法与在引用上调用方法等)虚拟成员函数基本上是指向函数的指针,该函数根据类层次结构实现指向要调用的正确函数。(注意,它不必是指针,但它通常是这样实现的,因为它似乎是这个抽象最有效的实现) 这表明知道将调用哪个函数只能在运行时确定 那么,如何内联一个只有在运行时才知道的函数呢?不可能 除非您有JIT编译器:)- 卓尔 对。这并不常见,您可能会在启动时失去一些性

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

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

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

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


除非您有JIT编译器:)- 卓尔

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

给定:

struct T {
   virtual void foo() { /* something */ }
};
使用多态性(如果您通过
指向T的指针
指向T的引用调用
foo()

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

静态分派(如果在bog标准对象上调用
foo()

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

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

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

不,虚拟函数确实可以内联。虚拟分派仅在以多态方式调用虚拟方法(即,在对象的指针或引用上)时使用。但是,当对对象值调用虚方法时,不会使用虚分派,编译器可以根据需要自由内联。

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

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

T* ptr = get_ptr_somehow();
ptr->T::foo();
注意,在这种情况下,指针和引用之间没有区别。在这两种情况下,都会得到运行时多态性

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

内联代码非常类似于将函数粘贴到可执行文件中需要的位置。未创建独立函数

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


我的建议是内联简单的、少于5行代码的方法,而不使用探查器。请记住,内联通常是将代码放在头文件中。更改方法的代码时,必须重新生成所有取决于头文件的转换单元。这在大型系统中可能代价高昂。一般来说,大块代码只有在经过验证后才能内联,并且只能按照分析器的指示提高效率。

除非您有JIT编译器:)哦,是的,当然。我要加上:多尔,如果你有
tx;x、 foo()
,对
foo()
的调用可以静态调度,因为
x
的动态类型已知为
T
@James:yes,很好。已编辑以合并此场景。为完整起见,即使通过指针,也可以通过直接调用禁用动态调度:
base*p=get_pointer();p->base::foo()
该调用是完全静态的,将由编译器解析,并且可能是内联的。@David:的确如此。为了完整性,我将添加这一点。:)严格地说,没有所谓的“阶级价值”。也许“对象值”可以起作用。:)@托马拉克·盖雷特·卡尔:很公平。
T* ptr = get_ptr_somehow();
ptr->T::foo();