修改基类需要子块重新编译吗?

时间:2013-07-25 10:36:25

标签: c++

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

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

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

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

语言没有明确定义(因为它没有解决动态链接问题),但是我们可以列出一些可行的案例,而且几乎肯定不会有些案例。

应该工作:

  1. 更改base.cpp中的非内联函数体
    • 只要未启用跨模块/链接时内联
    • 假设派生类不依赖于接口而不依赖于更改的行为
  2. 添加静态或非虚拟方法
    • 谨防改变重载决议
  3. 可能会非常失败:

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

    4. 这些假设背后有几个假设:

      1. 您的基类和派生类位于单独的动态库中(例如base.so和derived.so)。您的问题不清楚
      2. 运行时兼容性的唯一原因是
        • 因为内存中的布局发生了变化(即,您修改了基类实例大小,或者vtable大小,或者成员的大小或顺序)
        • 因为在调用站点生成 的代码发生了变化(即,因为您使用默认值添加了参数,或者将参数更改为可隐式可转换类型)
      3. 如果第一个假设不成立,那么问题似乎毫无意义,因为无论如何你都必须重建整个lib。

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

        关于内联,如果不同的动态库内联不同版本的代码,你可能会得到可怕的微妙错误。你真的不喜欢尝试调试那些。

答案 2 :(得分:0)

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

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

减少重新编译的经典技巧是PIMPL idiom PIMPL 通过指向存储为原始类成员的实现类的指针来隐藏类的实现。请注意,原始类仅用作接口。所以如果实现被修改,接口就不行了,所以类的用户不需要重新编译。