2014-06-15 128 views
1

众所周知,我们可以使用纯虚析构函数,就像这样:如果从析构函数调用纯虚函数是UB,为什么我们可以使用纯虚拟desrtuctors?

struct A { 
    virtual ~A() = 0; 
}; 
A::~A() {} 

struct B : A {}; 

因为标准说,在10.4 [class.abstract] p2

纯虚函数如果调用需要被定义只用...( 12.4 [class.dtor])

后来在12.4 [class.dtor] p9

析构函数可以声明为虚拟的(10.3)或纯虚拟的(10.4);如果程序中创建了该类的任何对象或任何派生类,则应定义析构函数。

什么意味着上面的代码是完全有效 - A::~A可以是纯虚拟的,它被定义,B::~B隐式调用A::~A

到目前为止,这么好。
然后我读10.4 [class.abstract] p6

成员函数可以从一个构造(或析构函数)一个抽象类的调用;对于从这样的构造函数(或析构函数)创建(或销毁)的对象,直接或间接地对纯虚函数进行虚拟调用(10.3)的效​​果是未定义的。

但是,这正是我们在这里所做的 - 我们从析构函数调用纯虚函数A::~A

那么,是不是有某种矛盾?

+0

析构函数是一种特殊情况,因为即使它是纯虚拟的,它仍然必须有一个正文(按照标准)。未定义的部分适用于纯虚拟成员函数(可能没有定义)。 – StoryTeller

回答

3

没有收缩。

您可以从B的析构函数中调用A的虚拟析构函数。 A析构函数不是B的成员。

标准§9.3

成员函数类的定义中声明

功能,但不包括与朋友符( 11.3)声明的那些 ,被称为是类的成员函数

该标准规定存在虚拟呼叫时存在未定义的行为摘要类的析构函数/构造函数(在你的情况下,它将是类A)到它自己的纯虚函数中的一个。

[...]的成员函数可以从一个抽象类[构造(或析构函数)被调用...]。

你的引证说析构函数:

  1. 您可以从一个抽象类
  2. 的析构函数从的调用成员函数如果调用纯虚方法(用虚拟呼叫)这个抽象类的析构函数,存在未定义的行为。
+0

以及如果'B'会是一个抽象类呢?那么它会是UB? – Abyx

+0

不,那里我不清楚,看到我的编辑。 – quantdev

-2

如果存在虚拟调用(10.3 [class.virtual]),则会发生UB。

对纯虚函数进行虚拟调用(10.3)的影响未定义。

但10.3 [class.virtual] P15说

与范围操作者(5.1)显式资格抑制虚拟调用机制。

隐式析构函数调用似乎具有明确的限定条件。
至少编译器肯定不会在那里做虚拟调用。