C++ - 需要重新编译时

q09*_*987 17 c++

您有一个许多库依赖的类.您需要修改一个应用程序的类.以下哪些更改需要在构建应用程序之前重新编译所有库?

  • 添加一个构造函数
  • 添加数据成员
  • 将析构函数更改为虚拟
  • 将具有默认值的参数添加到现有成员函数

谢谢

dor*_*ron 30

类在头文件中定义.头文件将被编译到实现该类的库和使用该类的代码中.我假设您正在考虑在更改类头文件后需要重新编译类实现,并且您要问的问题是您是否需要重新编译引用该类的任何代码.

您描述的问题是二进制兼容性(BC)之一,通常遵循以下规则:

  1. 在类中的任何位置添加非虚函数不会破坏BC.
  2. 更改任何函数定义(添加参数)将破坏BC.
  3. 在任何地方添加虚函数都会改变v表,从而破坏BC.
  4. 添加数据成员将破坏BC.
  5. 将参数从非默认值更改为默认值不会破坏BC.
  6. 对内联函数的任何更改都将破坏BC(因此,如果BC很重要,则应避免使用内联函数.)
  7. 更改编译器(有时甚至是编译器版本)可能会破坏BC,除非编译器严格遵守相同的ABI.

如果BC是您正在实现的平台的主要问题,那么使用Bridge模式分离接口和实现是一个好主意.

另外,C++语言不涉及应用程序二进制接口(ABI).如果二进制兼容性是一个主要问题,您可能应该参考您平台的ABI规范以获取更多详细信息.

编辑:更新添加数据成员.这将打破BC,因为现在需要比以前更多的内存.


sbi*_*sbi 13

严格来说,一旦您因任何原因不重新编译,您就会进入Undefined Behavior.

也就是说,在实践中你可能会侥幸逃脱:

  • 添加一个构造函数

可以使用,只要使用

  1. 它不是该类的第一个用户定义的构造函数
  2. 它不是复制构造函数
  • 添加数据成员

这会更改类实例的大小.对于那些只使用指针或引用的人来说,如果你注意将这些数据放在所有其他数据之后,那么访问其他数据成员的偏移量就不会改变.但是没有定义二进制中子对象的确切布局,因此您将不得不依赖于特定的实现.

  • 将析构函数更改为虚拟

这会更改类的虚拟表,因此需要重新编译.

  • 将具有默认值的参数添加到现有成员函数

由于默认参数是在调用站点插入的,因此使用它的每个人都需要重新编译.(但是,使用重载而不是默认参数可能会让你侥幸逃脱.)

请注意,任何内联成员函数都可能呈现上述任何错误,因为这些代码的代码直接嵌入(和优化)在客户端代码中.

但是,最安全的选择是重新编译所有内容.为什么这是一个问题?

  • 好答案.有些老师有时会关注奇怪的事情.任何使用体面的makefile系统的人都不应该关心重新编译和更改. (2认同)