1

假设我有一个基类和一个派生类。我已经编译了我的程序并运行它。现在假设我想在我的基类中做一些改变。
我的问题是:

  • 问题 1:如果我仅在基类文件中单独进行更改并仅重新编译基类,那么这些更改是否会反映在已经实例化的派生类对象中,或者我是否还需要重新编译派生类。问这个问题的其他方式可能是副本是创建到基类成员函数还是存储指针以便自动反映更改?

  • 问题2:如果没有自动更新,那么有什么办法可以做到这一点??

4

3 回答 3

1

C++ 没有反射,所以你需要重新编译整个东西。

于 2013-07-25T10:38:15.273 回答
1

这不是由语言明确定义的(因为它不涉及动态链接),但我们可以列出一些可能有效的情况,而有些情况几乎肯定不会。

应该管用:

  1. 更改 base.cpp 中的非内联函数体
    • 只要未启用跨模块/链接时内联
    • 假设派生类不仅仅依赖于接口而不依赖于改变的行为
  2. 添加静态或非虚拟方法
    • 不过要小心改变重载分辨率

可能会严重失败:

  1. 更改派生类中使用 的任何方法或构造函数的原型
    • 这包括在调用代码中通常不可见的更改(例如添加默认参数)或更改参数的类型,即使存在隐式转换等。
  2. 添加、删除或重新排序虚拟方法
  3. 添加、删除或重新排序数据成员或基类

这些背后有几个假设:

  1. 您的基类和派生类位于不同的动态库中(例如 base.so 和 derived.so)。从您的问题中不清楚
  2. 运行时兼容性中断的唯一原因是
    • 因为内存中的布局发生了变化(即,您修改了基类实例大小,或 vtable 大小,或成员的大小或顺序)
    • 因为在调用站点生成的代码已更改(即,因为您添加了具有默认值的参数,或者将参数更改为隐式可转换类型)

如果第一个假设不成立,那么这个问题似乎毫无意义,因为无论如何您都必须重建整个库。

如果您更改或升级编译器,或更改编译器标志或您链接的任何其他库的版本,则第二个假设可能会被打破。

关于内联,如果不同的动态库内联了不同版本的代码,您可能会遇到非常微妙的错误。你真的不会喜欢尝试调试这些。

于 2013-07-25T11:26:56.860 回答
0

C++ 是一种静态编译语言。这意味着每次类型检查都是在编译时完成的,所以如果你修改了一个类型,那么依赖于修改的每一行代码都必须重新编译。它包括基类修改和子类,就像您的情况一样。

请注意,这可能是一个问题,因为如果您正在编写 API,并且修改了 API 实现,则必须重新编译 API 和使用您修改的代码(用户代码)的每个代码。

减少重新编译的经典技术是PIMPL 习惯用法PIMPL通过指向存储为原始类成员的实现类的指针隐藏类的实现。请注意,原始类仅充当接口。所以如果修改了实现,接口就没有了,所以类的用户不需要重新编译。

于 2013-07-25T11:02:11.673 回答