0

考虑接下来的两个课程:

struct Base
{
  virtual ~Base()
  {
  }

  virtual void foo() = 0;
};

struct Derived : public Base
{
  virtual void foo()
  {
  }
};

以下是否导致未定义的行为:

Base *obj = new Derived;
delete obj;

?

附加问题:为什么一个方法被声明为虚拟的,它在派生类中是虚拟的(即使在派生类中没有使用 virtual 关键字),但对于析构函数却不是这样?

4

4 回答 4

4

以下是否导致未定义的行为:

不,这并不是Base因为is的析构函数而调用未定义的行为virtual


编辑:它只是为了澄清一个疑问(在下面的评论中提出),并强调我上面所说的。

@Oli Charlesworth 评论道:

从技术上讲,即使它没有被声明为虚拟的,行为也不会是未定义的,它只是不可取的。

不,行为将是未定义的。

标准中的§5.3.5/3 部分说,

在第一种选择(删除对象)中,如果操作数的静态类型与其动态类型不同,则静态类型应为操作数动态类型的基类,并且静态类型应具有虚拟析构函数或行为未定义. 在第二种选择(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,则行为未定义。

我认为这有助于消除疑虑。:-)

于 2011-04-19T11:56:05.050 回答
2

这不是未定义的行为。您已将基类析构函数声明为virtual,因此在运行时,delete obj将首先调用 in 中的“默认”析构函数Derived(因为您尚未显式声明一个),然后调用 in 中的析构函数Base

于 2011-04-19T11:55:36.940 回答
1

对于任何类,构造函数和析构函数都不会被继承。这是在标准中规定的。因此,您的代码不会导致未定义的行为,因为它将调用该类的默认构造函数/析构函数。
正是由于这个原因,继承不适用于析构函数/构造函数。从父对象继承构造函数/析构函数是没有意义的,因为该对象可能具有所有形式的不同成员。

于 2011-04-19T11:55:30.823 回答
1

由于您已将基类的析构函数声明为虚拟,因此这里没有未定义的行为。

声明:

Base *obj = new Derived;
delete obj;

将导致调用派生类的析构函数,然后调用基类的析构函数。虽然我没有得到第二个问题

于 2011-04-19T11:59:09.950 回答