我正在尝试了解虚拟析构函数。以下是此页面When to use virtual destructors?
的复制粘贴在这里,您会注意到我没有声明Base的析构函数 虚拟。现在,我们来看看以下片段:
Base *b = new Derived(); // use b delete b; // Here's the problem!
[...]如果要阻止通过基类指针删除实例,可以使基类析构函数受保护且非虚拟;通过这样做,编译器将不允许您在基类指针上调用delete。
我不明白为什么通过拥有受保护的非虚基类析构函数来阻止删除。编译器是否认为我们试图从基类对象中调用delete
? protected
与此有什么关系?
答案 0 :(得分:9)
C ++标准对此有delete
(第5.3.5p10节):
对释放函数和析构函数(12.4,12.5)进行访问和模糊控制。
因此,只有有权访问析构函数的代码才能使用delete
。由于析构函数是protected
,这意味着没有人可以在delete
类型的指针上调用Base*
。只有子类可以使用析构函数(并且唯一的东西是子类自己的析构函数,作为子对象销毁过程的一部分)。
当然,子类应该创建自己的析构函数public
,允许您通过子类类型删除对象(假设它是正确的实际类型)。
注意:实际上,Base
的其他成员可以访问delete (Base*)p;
{{1}}。但是C ++假定使用这种结构的人不会这样做--C ++访问控制只为你班级以外的代码提供指导。
答案 1 :(得分:5)
delete b;
有效执行b->~Base(); deallocate(b);
。第一部分 - 调用析构函数 - 如果析构函数不可访问将无法编译(与调用任何其他不可访问的方法失败的方式相同)。
答案 2 :(得分:0)
根据我的理解(基于此page),我们希望在基类中使用非虚拟和受保护的析构函数的唯一情况如下:
IsOdd *a = new IsOdd;
delete a;
因此,你只能这样做:
IsOdd c;
或
unary_function *a = new IsOdd;
delete a;
永远不会:
void f(unary_function *f) {
delete f;
// this function couldn't get compiled because of this delete.
// you would have to use the derived class as the parameter
}
因此,对于非虚拟保护的析构函数,当您尝试使用此编译器时编译器会出错
CASE