1

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

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

4

3 回答 3

3

形式上,如果您不重新编译,您将违反单一定义规则,并获得未定义的行为。

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

于 2012-02-08T05:16:41.397 回答
0

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

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

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
于 2012-02-08T05:11:06.907 回答
-1

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

于 2012-02-08T06:46:21.257 回答