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

时间:2019-06-03 17:15:23

标签: c++ c++11 virtual-functions vtable

我试图了解一个类的vtable在C ++中的敏感程度,为此,我需要知道对于3种更改情况,是否需要重新编译整个类层次结构(总共3个头文件)下面列出。首先,这是我的班级层次结构:

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. 将非虚拟方法添加到基类A:

    void method3() {};
    
  2. 带有主体的虚拟方法被添加到基类A:

    virtual void method3() {};
    
  3. 一个纯虚拟方法被添加到基类A:

    virtual void method3() = 0;
    

在方案1中,未对vtable进行任何更改。仍然需要重新编译B和C吗?

在方案2中,是否会针对基数A并因此针对B和C重构vtable?

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

2 个答案:

答案 0 :(得分:7)

C ++一键定义规则清楚地表明,如果要将它们链接在一起,则不同翻译单元(即文件)中实体的定义必须相同。因此,如果您完全更改了类的定义,包括公共,私有,virtual,非{virtual任何内容,则所有使用该定义的翻译单元都必须正在查看新的类定义。这将需要重新编译。

此操作失败,但没有诊断信息(链接器错误)。因此,您的项目似乎可以很好地链接。确实,在某些情况下它实际上可能起作用。但是,没有任何东西可以保证它们在哪种情况下可以工作,在哪种情况下不能工作。

答案 1 :(得分:2)

不管缺少virtual的{​​{1}}析构函数,您在这里都有一个界面

A

接口是一个不应被破坏的合同。

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

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() {}
};