在基类更改后重新编译

时间:2012-02-08 05:06:31

标签: c++ compilation recompile

  

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

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

3 个答案:

答案 0 :(得分:3)

正式地说,如果你不重新编译,你违反了一个定义规则,并得到了未定义的行为。

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

答案 1 :(得分: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

答案 2 :(得分:-1)

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