在C++中,覆盖现有的虚函数会破坏ABI吗?

Jos*_*vin 11 c++ virtual-functions backwards-compatibility abi subclassing

我的库有两个类,一个基类和一个派生类.在库的当前版本中,基类具有虚函数foo(),派生类不会覆盖它.在下一个版本中,我希望派生类可以覆盖它.这会破坏ABI吗?我知道引入一个新的虚函数通常会,但这似乎是一个特例.我的直觉是它应该改变vtbl中的偏移量,而不是实际改变表的大小.

显然,由于C++标准没有强制要求特定的ABI,这个问题在某种程度上是特定于平台的,但实际上,在大多数编译器中,断开和维护ABI是类似的.我对GCC的行为感兴趣,但是人们可以回答的编译器越多,这个问题就越有用;)

Mat*_* M. 9

它可能.

关于偏移,你错了.vtable中的偏移量已经确定.会发生什么是Derived类构造函数将使用Derived覆盖替换该偏移处的函数指针(通过将类内v-pointer切换到新的v-table).所以它通常是ABI兼容的.

但是,由于优化,特别是函数调用的虚拟化,可能存在问题.

通常,当您调用虚函数时,编译器会通过vpointer在vtable中引入查找.但是,如果它可以(静态地)推断出对象的确切类型,它还可以推断出调用和删除虚拟查找的确切函数.

例:

struct Base {
  virtual void foo();
  virtual void bar();
};

struct Derived: Base {
  virtual void foo();
};

int main(int argc, char* argv[]) {
  Derived d;
  d.foo(); // It is necessarily Derived::foo
  d.bar(); // It is necessarily Base::bar
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下...只是链接到你的新图书馆将无法接收Derived::bar.


Mar*_*k B 7

这看起来似乎并不是特别依赖的东西 - 正如你所说的C++ ABI非常棘手(甚至是编译器选项).

这就是说我认为您可以g++ -fdump-class-hierarchy在进行更改之前和之后使用,以查看父级或子级vtable是否在结构上发生变化.如果他们不这样做,那么假设你没有打破ABI可能是"相当"安全的.

  • 如果编译器能够对多个函数调用进行虚拟化,它会这样做:/ (2认同)