【问题标题】:Virtual override and binary compatibility虚拟覆盖和二进制兼容性
【发布时间】:2011-11-13 04:02:15
【问题描述】:

我有一个可以编译为共享库(或 Windows 中的 DLL)的库。它有一个派生自另一个库中的另一个类的类。基类有一些虚拟方法,我的类覆盖了其中的一些。例如:

class Base {
public:
    virtual void method1();
    virtual void method2();
    virtual void method3();
};

class Derived: public Base {
public:
    virtual void method2();
};

现在我发现其中一种虚拟方法不适用于我的班级。目前它没有覆盖这个方法,所以我也想覆盖它来修复它的行为:

class Derived: public Base {
public:
    virtual void method2();
    virtual void method3();
};

这会破坏与旧版本库的二进制兼容性吗?

据我了解,它与仅仅添加虚函数不同,因为 vtable 中虚方法的数量和顺序保持不变。唯一的区别是我的类的 vtable 中的特定条目现在将包含不同的值。这是正确的吗?

我也很确定当前使用我的库的应用程序都没有使用该方法,因为它已完全损坏并且永远无法工作。所以我不担心破坏对基本方法实现的现有调用。我只是想确保我不会破坏其他任何东西。

【问题讨论】:

  • 从逻辑上讲,听起来应该没问题。但我不确定在 C++ 中保持二进制兼容性的确切规则。

标签: c++ overriding virtual binary-compatibility


【解决方案1】:

既然您在谈论 DLL,我假设这是 Visual Studio/Windows 中的 C++。添加覆盖不会破坏二进制兼容性,因为 vtable 的大小没有改变。但是,如果您不重新编译所有实例化 Derived 的新实例的代码,则可能会导致一些不希望的结果。这是因为 vtable 是由实例化源初始化的,而不是实现 Derived 的类的源。

【讨论】:

  • 不,它是跨平台的,不仅仅是 Windows,我误用了 DLL 术语。无论如何,vtable 不只是 DLL 中的某种静态方法指针数组吗?而且我认为 vtable 指针是由构造函数初始化的。为什么实例化源会对这个过程产生任何影响?
  • vtable 不仅仅是一个静态数组,因为它实际上会在对象的生命周期内发生变化。在基类/派生类构造函数/析构函数中的调试器中查看它,您会看到方法指针会根据派生类是否已构造/析构而变化。
  • vtable 在构造函数被调用之前被初始化。它不能由声明类的模块分配,因为该类(以及从它派生的任何类)不知道表的最终大小,因为可能有派生添加的新虚拟。因此,它必须由实例化对象的模块分配。
  • 现在,语言本身没有定义/要求这种行为(甚至是 vtable 实现),但我知道在 Windows/VC++ 上是这样的。
  • vtable 指针(类实例中的字段)在初始化期间会发生变化,对,但它会在每个构造函数调用时发生。我的构造函数不是内联的,因此它位于 DLL 中,尽管是从应用程序调用的。 vtable 本身(vtable 指针指向的东西)对于层次结构中的每个类都是固定的,并且在编译时是已知的,因此它应该在编译时初始化并在重定位过程中在启动时进行调整。所以 vtable 和 vtable 指针都在 DLL 中初始化。我哪里错了?
【解决方案2】:

如果我理解正确,您在 Dll1 中有 Base 类,在 Dll2 中有 Derived 类。如果是这种情况,您描述的更改不会影响 Dll1。假设您将安装更新的 Dll2,只要您通过指针或对 Base 的引用访问 Derived 的实例,您的应用程序就会切换到调用 Derived::method3()。

【讨论】:

    【解决方案3】:

    您的派生类(添加了新的虚拟方法)所在的库不一定必须是与旧版本的库兼容的二进制 (ABI)。这是因为当您添加被覆盖的虚方法时,您无法控制编译器如何生成 vtable。

    【讨论】:

    • 但是我认为任何编译器都必须生成一个与基类兼容的vtable?而且那个 vtable 保持不变,我不会(也不能)改变它。
    猜你喜欢
    • 2013-01-30
    • 2011-10-08
    • 1970-01-01
    • 1970-01-01
    • 2015-10-11
    • 1970-01-01
    • 2020-05-12
    • 2011-08-03
    • 1970-01-01
    相关资源
    最近更新 更多