struct A
{
virtual ~A() { this->f(); }
virtual void f() {};
};
struct B : A
{
int* p;
B() : p(new int) {}
~B()
{
delete p;
p = 0;
}
void f() override { *p = 0; }
};
int main()
{
delete new B; // Is it safe?
}
在虚拟析构函数中调用其他虚方法是否安全?
答案 0 :(得分:2)
如果你知道规则是安全的,并且规则说在析构函数中,对象的动态类型是析构函数正在执行的类。
正在执行B::~B()
时,对象的类型为B
(如果您拨打f()
,则会发送给B::f()
当A::~A()
正在执行时,对象的类型为A
,如果您调用f()
,则根据§10.4得到未定义的行为[class.abstract] / 6 < / p>
可以从抽象类的构造函数(或析构函数)调用成员函数;对于从这样的构造函数(或析构函数)创建(或销毁)的对象,直接或间接地对纯虚函数进行虚拟调用的效果是未定义
或者,正如clang ++报告的那样,
test.cc:5:20: warning: call to pure virtual member function 'f'; overrides of 'f' in subclasses are not available in the destructor of 'A'
virtual ~A() { this->f(); }
^
test.cc:7:5: note: 'f' declared here
virtual void f() = 0;
^
1 warning generated.
编辑:OP编辑纯虚拟出..所以,当A::~A()
正在执行时,对f()
的虚拟调用将被调度到A::f()
答案 1 :(得分:1)
注意:OP编辑了代码以删除纯虚拟部分。
根据您发布的内容,不是不安全。当您在继承层次结构中的类的构造函数或析构函数中调用虚函数时,它不像往常一样调用派生函数最多,而是调用当前类中定义的函数。
在这种情况下,~A调用没有函数体的A :: f(),所以这是一个错误。如果你为A :: f()提供了一个主体(你可以使用纯虚拟,只是在类定义之外),那么它将是“安全的”,尽管它是否能满足您的需求是另一回事。