编译器是否真的强制执行纯虚析构函数?

时间:2017-08-31 06:57:14

标签: c++ compilation language-lawyer destructor pure-virtual

验证语句" 编译器&链接器强制存在纯虚析构函数的函数体。"从这个geeksforgeeks article开始,我编译了这段代码:

class Base
{
public:
    virtual ~Base()=0; // Pure virtual destructor
};

class Derived : public Base
{
public:
    ~Derived()
    {
        std::cout << "~Derived() is executed";
    }
};

int main()
{
    //Derived d;   <<<
    return 0;
}

编译没有任何错误。那么为什么编译器在这种情况下没有选择强制执行函数体的存在呢?

2 个答案:

答案 0 :(得分:10)

因为如果您执行ODR 1 违规,编译器(实际上整个翻译过程)没有 强制执行任何操作。根据{{​​3}}的C ++标准:

  

每个程序都应包含每个非内联的一个定义   在该程序中使用的函数或变量; 没有诊断   需要即可。定义可以在程序中明确显示,也可以   可以在标准库或用户定义的库中找到,或者(在   适当的)它是隐式定义的(见[class.ctor],[class.dtor]   和[class.copy])。应在每个中定义内联函数   翻译单位,使用它。

编译器完全有权找出你的程序实际上并没有使用 2 Derived的析构函数(因此Base的析构函数) ,只是不打扰通知你。

<子> 1 O ne D 定义 R ule
2 [basic.def.odr/4]

答案 1 :(得分:1)

  

编译器是否真的强制执行纯虚析构函数?

编译器没有这样做。

编译器将编译单元编译为目标文件,这就是

的原因
  

编译时没有任何错误。

我认为几乎每个编译器都会编译它而没有任何错误。但链接器会抱怨。编译器只是将代码添加到目标文件,以及链接器绑定的输入和输出引用(用于静态链接)。

当然,如果您再次对Derived d;行进行评论,则该计划不会关联,请参阅online demo

更新

您在问题中显示的只是一个编译单元,如果将其作为程序链接,链接器可能会删除未使用的代码。 StorryTeller's answer对此有很多说法。

如果您对main中的Derived用法进行评论并将Base类的定义复制到另一个编译单元并在那里添加析构函数实现,那么您将看到两者都将被链接在一起,生成的程序将运行没有任何错误。如果您是否包含标题中的定义,编译器本身并不在意。我并不建议将其用于高效编程,而是要理解为什么编译器传统上并不关心定义的完整性。大多数现实世界的编译单元通常都是不完整的。