如果将虚函数或非虚函数添加到 C++ 中的基 class,是否必须重新编译整个 class 层次结构?

Must the entire class hierarchy be recompiled if a virtual or non-virtual function is added to the base class in C++?

我正在尝试了解 class 的 vtable 在 C++ 中有多敏感,为此,我需要知道是否重新编译整个 class 层次结构(总共 3 个头文件) 对于我在下面列出的 3 个变更场景是必需的。首先,这是我的 class 层次结构:

class A {
   public:
   virtual void method1() = 0;
   virtual void method2() = 0;
   virtual ~A() {} 
};

class B : public A {
    public:
    virtual void method1() {};
    virtual void method2() {};
    virtual ~B() {} 
};

class C : public A {
    public:
    virtual void method1() {};
    virtual void method2() {};
    virtual ~C() {} 
};

这是我的场景:

  1. 一个非虚拟方法添加到基class A:

    void method3() {};
    
  2. 一个带主体的虚方法被添加到基class A:

    virtual void method3() {};
    
  3. 基础上增加了一个纯虚方法class A:

    virtual void method3() = 0;
    

在场景 1 中,没有对 vtable 进行任何更改。 B和C还需要重新编译吗?

在场景 2 中,是否会为基 A、B 和 C 重建 vtable?

我知道场景 3 将强制 classes B 和 C 提供新方法的实现。因此,必须重新编译整个层次结构。

尽管 A 缺少 virtual 析构函数,您在这里有一个 接口

class A {
   public:
   virtual void method1() = 0;
   virtual void method2() = 0;
   virtual ~A() {} // This is needed
};

接口是一个不应该被打破的契约。

如果您想扩展接口而不需要重新编译完整的代码库,您可以使用继承和动态多态性检查:

class AEx : public A {
public:
   virtual void method3() = 0;
   virtual ~AEx() {}
}; 

在处理扩展的函数中你可以做

void foo(A* pA) {
    AEx pAEx = dynamic_cast<AEx*>(pa);
    if(pAEx) {
       pAEx->method3();
    }
}

C++ one-definition-rule 清楚地表明,如果您要 link 他们在一起。因此,如果您完全更改 class、public、private、virtual、non-virtualwhatever,所有使用该定义的翻译单元都必须查看新的 class 定义。这将需要重新编译它。

未能做到这一点是 il-formed,但不需要诊断 (linker-error)。所以你的项目可能看起来 link 就好了。事实上,它在某些情况下可能确实有效。但是没有什么可以保证它们在哪些情况下会起作用,在哪些情况下不会起作用。