0

これについて質問があります:

class A
{
  int a;
  int* pa;
public:
   A(int i):a(i) , pa(new int(a))
   {
      cout<<"A ctor"<<a<<endl;
   }
   ~A()
    {
      delete pa;
      cout<<"dtor\n";
    }
    int * &get()
    {
     return pa;
    }
};

class B : public A
{
     int b;
public:
      B (A obj): A(obj) , b(0)
      {
       cout<<"B ctor\n";
      }
      ~B()
      {
       cout<<"B dtor\n";
      }
};

int main()
{
 int i = 23 ; 
 A* p = new B(i);
}

最後の行がmainコンパイルされる理由を教えてください。代わりにオブジェクトを期待するintintoのコンストラクターを渡します。はinのコンストラクタに変換されていると思いますが、なぜですか?BAintAB

前もって感謝します。

アヴリ。

4

3 に答える 3

5

Aコンパイラとしてコンストラクタを宣言していないため、インスタンスを初期化するためにそれを使用および使用explicitする無名インスタンスを作成しています。コンパイラにこれらの暗黙的な変換を行わせたくない場合は、コストラクタを として宣言します。次に、コンパイラ エラーが発生します。AiBexplicit

于 2011-02-05T10:24:49.430 に答える
2

を受け取り、マークされていないA単一のパラメーター コンストラクターがあるため、暗黙的に を に変換できます。intexplicitintA

を実行するnew B(i)と、 の唯一の実行可能なコンストラクターが を受け取るため、BA変換iし、そこからA新しいものを構築しようとBします。この変換はAint.

Bオブジェクトが構築されると、基本クラスは一時的なものAからコピー構築されます。Aこれは、メンバー変数aをコピーすることを意味しpa、一時的なA.

厳密には、コンストラクターはAオブジェクトを値で受け取るため、概念的には一時オブジェクトが再度コピーされます。Bただし、コンパイラはコンストラクターパラメーターを直接から構築することにより、一時的なものを削除するi場合があるため、効果は単一のコピーのように見える場合があります。

A一時オブジェクトが破棄されるdelete paと、動的に割り当てられたオブジェクトintが破棄されますが、新しく割り当てられたオブジェクトの基本クラス A にはB、無効なオブジェクトを指していないこのポインターのコピーが残っているため、これにより重大なエラーが発生します。コンパイラがコピーの 1 つを削除しない場合、「二重解放」がすぐに発生します。

の重要な側面Aは、リソース アクション (割り当て解除) を実行するユーザー定義のデストラクタがあることです。Aこれは、ユーザー定義のコピー コンストラクターとコピー代入演算子を必要とする強力な警告です。コンパイラによって生成されたバージョンは の設計と一貫して動作しない可能性があるためですA

これは「3 の規則」として知られており、デストラクタ、コピー コンストラクタ、またはコピー代入演算子のいずれかのユーザー定義バージョンが必要な場合、それらすべてのユーザー定義バージョンが必要になる可能性が高いということです。

この例で動的に割り当てられたBオブジェクトを解放しようとすると、「二重解放」エラーが発生する可能性があります。さらに、のデストラクタは、ポインタを介した削除が正しく機能Aするようにマークする必要があります。virtualA

于 2011-02-05T10:32:26.173 に答える
1

intからへの変換があるためA、コードは暗黙的に に変換されます。

 A* p = new B(A(i));
于 2011-02-05T10:27:12.867 に答える