基类更改后重新编译

发布于 2025-01-04 01:26:02 字数 185 浏览 1 评论 0原文

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

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

In particular, the way most C++ implementations work implies that a
change in the size of a base class requires a recompilation of all
derived classes.

This statement is from stroustrup book.
So if base class is in a .so file and we just change a member function implementation, then does it mean that we don't have to recompile my program linked to that shared object?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

请帮我爱他 2025-01-11 01:26:02

从形式上来说,如果你不重新编译,你就违反了“单一定义规则”,并会得到未定义的行为。

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

Formally, if you don't recompile you're violating the One Definition Rule, and get undefined behavior.

Practically, as long as the member function you modify hasn't been inlined anywhere, and you aren't changing the signature, you probably retain binary compatibility. On most platforms. If you're lucky, your platform documentation provides such a guarantee.

苄①跕圉湢 2025-01-11 01:26:02

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

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

之前

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

I believe your understanding is correct. Just changing the body of a member function doesn't change the amount of space required for an instance of that object. The code isn't stored "in" the object instance; only the data is.

When the class is compiled, references to member data fields are just offsets from the beginning of that object data. And derived classes' data are typically placed after the base class's data. So if you add a field to the base class, the correct offsets for the derived class data have all changed, which implies the base class needs recompiled, to point to the new (correct) offsets.

Before

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

After

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
欢烬 2025-01-11 01:26:02

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

If it just the implementation, it should work fine. That's whole concept of Windows DLL's. Adding or removing interfaces won't changes the class size (unless you're introducing a new virtual function) but in the large extend the way functions laid out in the memory could be changed. So a recompilation is required if you're making use of the new function. On the other hand, most of the modern compilers are smart enough to identify the relevant changes because of a simple modification in the header files.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文