简体   繁体   English

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

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

I am trying to learn how sensitive the vtable of a class is in C++ and, for that, I need to know whether recompilation of the entire class hierarchy (total, 3 header files) is necessary for the 3 change-scenarios I list below. 我试图了解一个类的vtable在C ++中的敏感程度,为此,我需要知道对于下面列出的3种更改方案是否需要重新编译整个类层次结构(总共3个头文件)。 First, here is my class hierarchy: 首先,这是我的班级层次结构:

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

Here are my scenarios: 这是我的情况:

  1. A non-virtual method is added to the base class A: 非虚拟方法被添加到基类A:

     void method3() {}; 
  2. A virtual method with a body is added to the base class A: 具有主体的虚拟方法被添加到基类A中:

     virtual void method3() {}; 
  3. A purely virtual method is added to the base class A: 将纯虚拟方法添加到基类A:

     virtual void method3() = 0; 

In scenario-1, no change to the vtable is made. 在方案1中,不对vtable进行任何更改。 Is it still required for B and C to be recompiled? 是否仍然需要重新编译B和C?

In scenario-2, will the vtable be reconstructed for base A, and consequently for B, and C? 在方案2中,是否会针对基数A并因此针对B和C重构vtable?

I know scenario-3 will force classes B and C to provide implementations for the new method. 我知道方案3将强制类B和C提供新方法的实现。 So, the entire hierarchy must be recompiled. 因此,必须重新编译整个层次结构。

The C++ one-definition-rule makes it clear that definitions of entities in different translation units (ie: files) must all be identical if you're going to link them together. C ++一键定义规则清楚地表明,如果要将它们链接在一起,则不同翻译单元(即文件)中实体的定义必须全部相同。 As such, if you change the definition of a class at all, public, private, virtual , non- virtual , whatever , all translation units that use that definition have to be looking at the new class definition. 这样,如果您完全更改了一个类的定义, 无论是 public,private, virtual ,non- virtual 还是what ,使用该定义的所有翻译单元都必须查看新的类定义。 And that will require recompiling it. 这将需要重新编译。

Failure to do this is il-formed, but no diagnostic (linker-error) is required. 失败的原因是不正确的,但是不需要诊断(链接程序错误)。 So your project may appear to link just fine. 因此,您的项目似乎可以很好地链接。 Indeed, it may actually work in some cases. 确实,在某些情况下它实际上可能起作用。 But there's nothing which guarantees in which cases they will work and in which cases they will not. 但是没有任何东西可以保证它们在某些情况下会起作用,而在某些情况下它们不会起作用。

Regardless the missing virtual destructor of A you have an interface here: 无论缺少A virtual析构函数如何,您都可以在此处拥有一个接口

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

An interface is a contract that shouldn't be broken. 接口是一个不应被破坏的契约。

If you want to extend interfaces without the need to recompile the complete codebase, you can use inheritance and dynamic polymorphism checks: 如果要扩展接口而无需重新编译完整的代码库,则可以使用继承和动态多态检查:

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

In functions which handle the extensions you can do 在处理扩展的功能中,您可以执行

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM