0

次の2つのクラスを検討します。

struct Base
{
  virtual ~Base()
  {
  }

  virtual void foo() = 0;
};

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

次の原因で未定義の動作が発生していますか?

Base *obj = new Derived;
delete obj;

追加の質問:メソッドが仮想として宣言され、派生クラスでは仮想であるのはなぜですか(派生クラスで仮想キーワードが使用されていない場合でも)が、デストラクタには当てはまりませんか?

4

4 に答える 4

4

次の原因で未定義の動作が発生していますか?

いいえ、のデストラクタがであるという理由だけで、未定義の動作を呼び出すことはありません。Basevirtual


編集:それは(次のコメントで提起された)疑問を明確にし、私が上で言ったことを強調するためだけのものです。

@オリチャールズワースはコメントしました:

技術的には、仮想として宣言されていなくても、動作が未定義になることはなく、望ましくないだけです。

いいえ。動作は未定義です。

規格のセクション§5.3.5/3は次のように述べています。

最初の選択肢(オブジェクトの削除)では、オペランドの静的型が動的型と異なる場合、静的型はオペランドの動的型の基本クラスであり、静的型は仮想デストラクタを持っているか、動作が未定義です。 。2番目の選択肢(配列の削除)では、削除するオブジェクトの動的タイプが静的タイプと異なる場合、動作は未定義です。

疑問を取り除くのに役立つと思います。:-)

于 2011-04-19T11:56:05.050 に答える
2

それは未定義の動作ではありません。基本クラスのデストラクタをとして宣言したvirtualので、実行時に、delete obj最初にで「デフォルト」のデストラクタを呼び出しDerived(明示的に宣言していないため)、次にでデストラクタを呼び出しますBase

于 2011-04-19T11:55:36.940 に答える
1

どのクラスでも、コンストラクタとデストラクタ継承されません。これは規格で指定されています。そのため、クラスのデフォルトのコンストラクタ/デストラクタを呼び出すため、コードが未定義の動作を引き起こすことはありません。
継承がデストラクタ/コンストラクタに当てはまらないのはこのためです。コンストラクタ/デストラクタが親オブジェクトから継承されることは意味がありません。このオブジェクトは、すべての形式の異なるメンバーを持つ可能性があるためです。

于 2011-04-19T11:55:30.823 に答える
1

基本クラスのデストラクタを仮想として宣言しているため、ここでは未定義の動作はありません。

声明:

Base *obj = new Derived;
delete obj;

派生クラスのデストラクタを呼び出してから、基本クラスのデストラクタを呼び出します。2番目の質問はありませんでした

于 2011-04-19T11:59:09.950 に答える