基类更改后重新编译

recompile after base class change

本文关键字:编译 新编译 基类      更新时间:2023-10-16

特别是,大多数C++实现的工作方式意味着基类大小的更改需要重新编译所有派生类。

这句话来自stroustrup的书。所以,如果基类在.so文件中,并且我们只更改了一个成员函数实现,那么这是否意味着我们不必重新编译链接到该共享对象的程序?

从形式上讲,如果不重新编译,就违反了一个定义规则,并得到未定义的行为。

实际上,只要您修改的成员函数没有在任何地方内联,并且您没有更改签名,就可能保持二进制兼容性。在大多数平台上。如果幸运的话,您的平台文档提供了这样的保证。

我相信你的理解是正确的。仅仅更改成员函数的主体并不会更改该对象的实例所需的空间量。代码没有存储在对象实例中;只有数据是

编译类时,对成员数据字段的引用只是从该对象数据开头的偏移量。派生类的数据通常放在基类的数据之后。因此,如果向基类添加一个字段,则派生类数据的正确偏移量都会发生变化,这意味着基类需要重新编译,以指向新的(正确的)偏移量。

之前

class Foo {
    int a;              // offset 0 (assuming no vtable)
}
class Bar : public Foo {
    int b;              // offset 4
}
Bar bar;  bar.b = 7;    // sets the 32-bit value at this+4 to 7

之后

class Foo {
    int a;              // offset 0
    int c;              // offset 4
}
class Bar : public Foo {
    int b;              // offset 8
}
Bar b;   bar.b = 7;     // Without recompiling: sets the 32-bit value at this+4
                        //   which is actually where Foo.a is stored!
                        // With recompiling: sets the 32-bit value at this+8

如果只是实现,它应该可以正常工作。这就是Windows DLL的全部概念。添加或删除接口不会改变类的大小(除非你引入了一个新的虚拟函数),但在很大程度上可以改变内存中的函数布局。因此,如果使用新函数,则需要重新编译。另一方面,由于对头文件进行了简单的修改,大多数现代编译器都足够聪明,能够识别出相关的更改。