验证语句" 编译器&链接器强制存在纯虚析构函数的函数体。"从这个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;
}
编译没有任何错误。那么为什么编译器在这种情况下没有选择强制执行函数体的存在呢?
答案 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
类的定义复制到另一个编译单元并在那里添加析构函数实现,那么您将看到两者都将被链接在一起,生成的程序将运行没有任何错误。如果您是否包含标题中的定义,编译器本身并不在意。我并不建议将其用于高效编程,而是要理解为什么编译器传统上并不关心定义的完整性。大多数现实世界的编译单元通常都是不完整的。