特别是,大多数 C++ 实现的工作方式意味着基类大小的更改需要重新编译所有派生类。
此声明来自 stroustrup 书。因此,如果基类在一个.so
文件中,而我们只是更改了成员函数的实现,那么这是否意味着我们不必重新编译链接到该共享对象的程序?
特别是,大多数 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 的全部概念。添加或删除接口不会改变类的大小(除非你引入了一个新的虚函数),但在很大程度上,内存中的函数布局方式可能会改变。因此,如果您要使用新功能,则需要重新编译。另一方面,由于头文件中的简单修改,大多数现代编译器都足够聪明,可以识别相关更改。