c++ - 如果我在明确的情况下使用指针,编译器可以内联虚函数吗?

标签 c++ compiler-construction virtual inline

我已经读过 Are inline virtual functions really a non-sense? .但我仍然有一些疑问,在那里没有找到答案。

他们说如果情况没有歧义,编译器应该内联虚函数

但是:

This can happen only when the compiler has an actual object rather than a pointer or reference to an object.

如果我有一个从 A 派生的 B 类(它包含一个 virtual void doSth() 函数)并且我使用 B* 指针,而不是 A*:

B* b = new B;

b->doSth();
  1. 假设 B 没有任何子类。很明显(在编译时)应该调用什么函数。所以可以内联。是真的吗?
  2. 假设 B 有一些子类,但这些类没有自己的 doSth() 函数。所以编译器应该“知道”唯一要调用的函数是 B::doSth()。我猜它不是内联的?

最佳答案

是否B并不重要有任何派生类。在那种情况下b指向 B对象,以便编译器可以内联调用。

当然,任何体面的现代编译器都可以并且会在您的情况下做到这一点。如果你不使用指针,它会变得容易得多。那不是真正的“优化”。仅查看 . 左侧的 AST 节点,您就可以忽略虚拟调用这一事实变得显而易见。 -运算符(operator)。但是如果你使用指针,你需要跟踪指针对象的动态类型。但是现代编译器能够做到这一点。

编辑:一些实验是有序的。

// main1.cpp
struct A {
  virtual void f();
};

struct B : A { 
  virtual void f();
};

void g() {
  A *a = new A;
  a->f();

  a = new B;
  a->f();
}

// clang -O2 -S -emit-llvm -o - main1.cpp | c++filt
// ...
define void @g()() {
  %1 = tail call noalias i8* @operator new(unsigned int)(i32 4)
  %2 = bitcast i8* %1 to %struct.A*
  %3 = bitcast i8* %1 to i32 (...)***
  store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @vtable for A, i32 0, i32 2) to i32 (...)**), i32 (...)*** %3, align 4
  tail call void @A::f()(%struct.A* %2)
  %4 = tail call noalias i8* @operator new(unsigned int)(i32 4)
  %5 = bitcast i8* %4 to i32 (...)***
  store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @vtable for B, i32 0, i32 2) to i32 (...)**), i32 (...)*** %5, align 4
  %tmp = bitcast i8* %4 to %struct.B*
  tail call void @B::f()(%struct.B* %tmp)
  ret void
}
// ...

可以看出,clang 确实直接调用了 f , 两者都是 a指向 A当它指向 B 时. GCC 也是这样做的。

关于c++ - 如果我在明确的情况下使用指针,编译器可以内联虚函数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6836401/

相关文章:

c# - c# 编译器比 VB.NET 编译器更聪明吗?

c++ - 可以在基类中定义复制构造函数并仍然处理派生类情况吗?

c++ - 完美转发构造函数和删除构造函数

c++ - 我可以执行哪种技术并同时获得相同功能的输出?

c++ - C++中一组函数的静态变量

compiler-construction - LR(1) 文法和运算符优先文法有什么区别?

c++ - C/C++ 编译器会优化这个 if 语句吗?

C# 在不知道它是子类实例的情况下调用重写的子类方法

钻石设计中最后派生的 C++ 基类函数调用

java - 如何将 Eclipse C++ 添加到 Eclipse 经典?