【问题标题】:Is it necessary to rebuild all the binaries that is using a class inside a binary with virtual function?是否有必要重建所有在具有虚函数的二进制文件中使用类的二进制文件?
【发布时间】:2021-11-05 00:48:31
【问题描述】:

我有一个二进制 ABC.dll,它有一个 A 类,里面有虚函数。

ABC.dll

class A
{
    /* variables*/
    public:
    virtual func1(int x, int y, int z);
    /* other member functions and virtual functions*/
}

还有其他二进制文件正在创建此类的对象并使用其成员。

例如LIB.dll

A *obj = new A(/* constructor arguments*/);

以及其他使用此类的 dll。

现在我的软件有 ABC.dll、LIB.dll 和所有其他 dll,并且软件运行正常。 请注意,我上面的虚函数不会在任何其他二进制文件中的任何地方调用。

现在我需要更改虚函数的函数定义,为其添加参数化变量。

class A
{
    /* variables*/
    public:
    virtual func1(int x, int y, int z, int newVal = 0);
    /* other member functions and virtual functions*/
}

因此,在此处进行此更改后,我是否需要构建使用此 class A 的所有其他二进制文件或仅构建此二进制文件?

由于我的代码库很大,很难遍历每个项目并找到当前使用的地方。

如果我需要再次构建所有使用此class A 的 dll 并将其替换到我的软件位置,那么原因是什么。

当前问题:如果我不构建依赖项并在我的软件中替换它们,则当前正在使用此 dll 的进程正在崩溃。

如果是非虚函数,情况会一样吗?

注意:我也在那个实现这个虚函数的 dll 中进行了更改

【问题讨论】:

  • 您正在更改公共 API,因此您必须重建所有内容!如果您在 dll-s 之间进行继承,那么即使添加虚函数也需要重建所有内容。
  • 然而早些时候,当我没有使用任何虚拟功能时,该软件的进程并没有崩溃
  • 我正在谈论的公共API(func1)目前没有在其他dll中使用。
  • 虚拟与否在这种情况下并不重要。您正在添加额外的参数,因此您必须重建所有内容。默认值意味着编译器会默默地添加缺失值,函数总是需要 4 个参数。
  • 但问题是我更改的函数没有在其他 dll 中的其他任何地方调用

标签: c++ visual-studio dll binary virtual-functions


【解决方案1】:

更改 A 中的函数会更改它在二进制文件中的签名/位置,因此您的依赖库现在可能会尝试从不正确的偏移量执行该函数,因为它没有重新链接以知道 A 中的函数现在所在的位置。

【讨论】:

    【解决方案2】:

    当您更改任何函数的原型时,您正在破坏二进制兼容性。如果函数是虚拟的,它不会变得更丰富。

    为额外参数提供默认值可让您保持源代码兼容性,但会破坏二进制兼容性。参数的默认值意味着如果编译器看到该函数的调用缺少参数,他必须隐含地将这个具有默认值的额外参数添加到调用代码中。这意味着需要重建调用者。

    现在,既然您正在修改一个虚拟函数,那么您别无选择,您必须重新构建所有内容。 如果这个函数不是虚拟的,那么你可以提供一个重载,这样旧的原型仍然有效。 对于虚函数:添加、删除或更改 API 甚至更改它的顺序,都会破坏二进制兼容性。这就是为什么过载无法拯救的原因。

    【讨论】:

    • 我怀疑调用者 dll 无论如何都用 3 个参数调用它,那么为什么需要再次构建它
    • 我也明白你想说什么,但你不认为还有另一个问题,因为在其他使用 virtualfunc 的 dll 中将有 vptr 和 vtable 以及函数定义 func1(int x, int y, int z) 但现在由于我们更改了它,vtable 也需要更改,因为函数定义已更改为 func1(int x, int y, int z, int newVal = 0);,因此它的地址也是如此,因为地址是在编译时确定的
    • 再一次,默认值对从 dll 导出的函数没有影响。始终使用所有参数调用函数。默认值指示编译器在调用函数时添加缺少的参数。
    • 所以你的意思是像我调用这个函数的另一个dll一样,在那里函数本身将使用默认参数值调用。对于 rg,如果在其他 dll 中调用为 func1(1,2,3),那么编译器将自己添加 func1(1,2,3,0) ,其中 0 是调用此函数时的默认值?
    • 在此处查看默认值的工作原理:cppinsights.io/s/e86fefce
    猜你喜欢
    • 2014-09-03
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 2010-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-25
    相关资源
    最近更新 更多