C++ 关于用C+重新编译库的问题+;

C++ 关于用C+重新编译库的问题+;,c++,C++,假设我的类依赖于其他库。现在我需要修改一个应用程序的类。什么样的修改会迫使我重新编译 所有图书馆。重新编译所有库的规则是什么 例如,我只知道案例2)是这样的。其他的呢 1) 添加构造函数 2) 添加数据成员 3) 将析构函数更改为虚拟函数 4) 将具有默认值的参数添加到现有成员函数中如果您仅使用这些库,则不会强制您重新编译它们 除了更改编译器/体系结构/操作系统或更改一些库的#defines之外,这个问题有点让人困惑,所以要解决这个问题,您只需要重新编译依赖于您的类的代码 然后,对于依赖于您的课

假设我的类依赖于其他库。现在我需要修改一个应用程序的类。什么样的修改会迫使我重新编译 所有图书馆。重新编译所有库的规则是什么

例如,我只知道案例2)是这样的。其他的呢

1) 添加构造函数

2) 添加数据成员

3) 将析构函数更改为虚拟函数


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

如果您仅使用这些库,则不会强制您重新编译它们


除了更改编译器/体系结构/操作系统或更改一些库的
#define
s

之外,这个问题有点让人困惑,所以要解决这个问题,您只需要重新编译依赖于您的类的代码

然后,对于依赖于您的课程的内容:

  • 将构造函数添加到类中会引入一个新函数,因此如果客户端代码不使用该构造函数,则无需重新编译,
  • 添加数据成员会更改类的内存布局-需要重新编译,
  • 将析构函数更改为虚拟更改/引入vtable布局和功能分派代码-需要重新编译,
  • 将具有默认值的参数添加到现有成员函数会更改该函数的参数数量(默认参数在调用站点被替换)-需要重新编译客户端代码。
    你真的是说你要改变的课程取决于图书馆吗?您永远不必重新编译库,因为您已经更改了依赖于库的内容。如果更改库所依赖的内容,则需要重新编译库

    <> >答案是,在C++中,技术上所有这些都需要重新编译使用类的任何东西。如果所有单元中的定义完全相同,“一个定义”规则只允许在多个翻译单元中定义类(我认为“完全”是指预处理后相同的标记序列,在这种情况下,即使更改参数名称也需要重新编译)。因此,如果不同的源文件共享一个头,并且该报头中的类定义发生变化,C++就不会保证如果只有一个源文件被编译,那么编译的代码是否仍然兼容。

    但是,你的C++实现将使用静态/动态库格式来放松规则,允许一些修改为“二进制兼容”。在您列出的内容中,只有(1)有很大的机会实现二进制兼容。你必须检查你的文档,但可能没问题。通常(2)更改对象的大小和布局,(3)更改调用者销毁对象所需的代码,(4)更改函数的签名(默认值由调用代码插入,而不是由被调用者插入)

    出于这个原因,避免使用默认参数通常是值得的。只需添加另一个过载。因此,与其改变,不如:

    void foo(int a);
    

    替换为:

    void foo(int a) { foo(a, 0); }
    void foo(int a, int b);
    

    当然,如果用户使用指向函数foo的指针,则前一个更改甚至与源代码不兼容,更不用说二进制兼容了。后者是源兼容的,前提是解决了使用
    foo
    的歧义。C++确实会帮助这个,初始化函数指针是一个罕见的(只有)上下文影响表达式的值的情况。

    < P>改变库所依赖的任何源代码或类应该迫使重新编译库。一个好的构建工具,正确设置依赖项,将在构建过程中自动处理此问题。

    您只需要重新编译依赖于您的类的代码(如Nikolai所说),即您的类驻留在其他人使用的库中。 即使如此,只有在类满足以下条件时,您才需要重新编译依赖代码:

  • 更改其内存布局:
    • 添加/删除成员
    • 改变成员类型
    • 添加虚拟方法或将现有方法更改为虚拟方法(因此添加隐藏的vpointer成员)
  • 更改方法签名(更准确地说,更改编译器用于名称修饰/损坏的内容):
    • 改变他们的常态
    • 改变他们的虚拟性
    • 添加/更改默认参数值
  • 我很确定我错过了一些东西,但我会添加任何其他出现的东西(无论是从评论中还是如果我的记忆力开始好转的话)

    void foo(int a) { foo(a, 0); }
    void foo(int a, int b);