たとえば、コンストラクターを宣言しない場合、コンパイラーは、引数も定義も持たない (空の本体) デフォルトのコンストラクターを提供するため、何のアクションも実行しません。
たとえば、オブジェクトを使い終わった場合、デフォルトのデストラクタはオブジェクトが使用するメモリを再割り当て (解放) しませんか? そうでない場合、なぜ私たちはそれを取得しているのでしょうか?
そして、おそらく同じ質問がデフォルトのコンストラクターにも当てはまります。何もしない場合、なぜデフォルトで作成されるのでしょうか?
たとえば、コンストラクターを宣言しない場合、コンパイラーは、引数も定義も持たない (空の本体) デフォルトのコンストラクターを提供するため、何のアクションも実行しません。
たとえば、オブジェクトを使い終わった場合、デフォルトのデストラクタはオブジェクトが使用するメモリを再割り当て (解放) しませんか? そうでない場合、なぜ私たちはそれを取得しているのでしょうか?
そして、おそらく同じ質問がデフォルトのコンストラクターにも当てはまります。何もしない場合、なぜデフォルトで作成されるのでしょうか?
コンパイラーによって生成されたデフォルトのコンストラクターがアクションを実行しないと言うのは誤りです。これは、本体と初期化子リストが空のユーザー定義コンストラクターと同等ですが、アクションを実行しないという意味ではありません。これが何をするかです:
また、クラスがポリモーフィックでなく、基本クラスがなく、構築が必要なメンバーがない場合にのみ、コンパイラーによって生成されたデフォルトのコンストラクターは何もしません。ただし、それでも、他の回答で説明されている理由により、デフォルトのコンストラクターが必要になる場合があります。
デストラクタについても同じことが言えます。基本クラスのデストラクタと、それらを持っているすべてのメンバーのデストラクタを呼び出すため、コンパイラで生成されたデストラクタが何もしないというのは一般的なケースではありません。
しかし、メモリ割り当ては実際にはこれとは何の関係もありません。メモリはコンストラクタが呼び出される前に割り当てられ、最後のデストラクタが終了した後にのみ解放されます。
(一般にアクセス可能な) コンストラクタまたはデストラクタがない場合、クラスのオブジェクトをインスタンス化できないためです。検討:
class A
{
private:
A() {}
~A() {}
};
A a; // Oh dear! Compilation error
コンストラクターまたはデストラクターを明示的に宣言しない場合、コンパイラーはオブジェクトの作成を許可するものを提供する必要があります。
スマート ポインターを使用する場合、既定のデストラクタ (Sergey の回答を参照) は、メモリ リークを回避するために重要になる可能性があります。ここに例があります:
#include <iostream>
#include <memory>
using namespace std;
class Foo {
public:
Foo(int n = 0): n(n) { cout << "Foo(" << n << ")" << endl; }
~Foo() { cout << "~Foo(" << n << ")" << endl; }
private:
int n;
};
// notes:
// * default destructor of Bar calls destructors of unique_ptr<Foo> foo
// and of unique_ptr<Foo[]> foo3, which, in turn, delete the Foo objects
// * foo2's Foo object leaks
class Bar {
public:
Bar(): foo(new Foo(1)), foo2(new Foo(2)), foo3(new Foo[2]) { }
private:
unique_ptr<Foo> foo;
Foo* foo2;
unique_ptr<Foo[]> foo3;
};
int main() {
Bar bar;
cout << "in main()" << endl;
}
次の出力は、リークが次の場合にのみ発生することを示していますfoo2。
Foo(1)
Foo(2)
Foo(0)
Foo(0)
in main()
~Foo(0)
~Foo(0)
~Foo(1)
デフォルトのコンストラクタとデストラクタは、空のバージョンを手動で作成する必要がないクラスで特別なことをする必要がない場合の単なる商品です。これは、他の OO 言語に共通です。たとえば、Java では、メンバーのゼロ初期化で十分な場合、コンストラクターを提供する必要はありません。同時に、これは C との下位互換性を確保するための要件です。C に がある場合struct、コンストラクタまたはデストラクタはありません (C にはこれらの概念がありません)。有効なコード。
別のオプションは、クラスがコンストラクターまたはデストラクターを持つことができないことを言語で宣言することでしたが、言語仕様全体で、一部の型にはコンストラクターとデストラクターがあり、他の型にはないという事実に対処する必要があります。言語がより複雑になり、指定が難しくなります。暗黙的に定義されたバージョンを使用しても動作は変わらず、仕様が緩和されます。
このレベルでは、オーバーライドという用語が基本クラスのメソッドに適用されるようなものです。基本クラスでは、何もオーバーライドしません。オーバーライドするものはありません! それでも、言語は、ベースで宣言された仮想の非純粋なメソッドがオーバーライドであることを明示的に述べています。これにより、特定の階層内の特定のメソッドにオーバーライドが存在しない場合、extre * または基本メソッドの実装を追加することなく、ポインターまたは参照を介してメソッドが呼び出されたときに最終的なオーバーライドが呼び出されることを仕様で簡単に指定できます。
デフォルトのデストラクタは何もしません (デフォルトのコンストラクタのように)。
デストラクタが実際に何かをする必要がある場合は、自分で定義する必要があります (例: いくつかのリソースを解放する)。
通常、3 つのルールに従う必要があることに注意してください。プログラムがデストラクタで何かを行う必要がある場合 (たとえば、リソースの解放)、コピー コンストラクタと代入演算子も提供する必要があります。C++ には、それらのデフォルト バージョンも用意されています (これも何もしません)。
デフォルトのコンストラクタ/デストラクタ/代入演算子/コピー コンストラクタは、何もする必要のない単純なクラスを処理する場合に便利です。特殊なケースとして POD があります。それら (C++0x より前) は、明示的なコンストラクターまたはデストラクタを持つことさえできません。
簡単に言えば、C++ では、何もしない場合でも、すべてのオブジェクトにコンストラクターとデストラクターが必要です。したがって、バックグラウンドでそれらを作成するコンパイラは、この要件を満たします。
より長い答えは、コンストラクターがクラスのメンバーの初期化を担当しているということです。既定のコンストラクターは、すべてのメンバーの既定の初期化を行います。(これは POD 型には何の意味もありませんが、他のクラスではデフォルトのコンストラクターが呼び出されます。)
デフォルトのデストラクタには、クラスが「所有」しているメモリを解放して解放できるかどうかを知る方法がありません。
デフォルトのコンストラクタ部分については、これに関するウィキペディアの記事を引用します...
C++ では、既定のコンストラクターは特定の状況で自動的に呼び出されるため、重要です。
- MyClass x;; のように、オブジェクト値が引数リストなしで宣言されている場合。または引数リストなしで動的に割り当てられます。たとえば、new MyClass; オブジェクトの初期化には、デフォルトのコンストラクターが使用されます。
- MyClass x[10];; など、オブジェクトの配列が宣言されている場合。または動的に割り当てられます。たとえば、new MyClass [10]。デフォルトのコンストラクターは、すべての要素を初期化するために使用されます
- 派生クラス コンストラクターがその初期化子リストで基底クラス コンストラクターを明示的に呼び出さない場合、基底クラスの既定のコンストラクターが呼び出されます。
- クラス コンストラクターが、初期化子リスト内のオブジェクト値フィールドのいずれかのコンストラクターを明示的に呼び出さない場合、フィールドのクラスの既定のコンストラクターが呼び出されます。
- 標準ライブラリでは、値が明示的に指定されていない場合、デフォルトのコンストラクターを使用して、特定のコンテナーが値を「入力」します。ベクトルを 10 個の要素で初期化します。これらの要素は、型のデフォルトで構築された値で埋められます。
上記の状況で、クラスにデフォルトのコンストラクターがない場合はエラーになります。コンパイラはデフォルトのコンストラクタを暗黙的に定義します
クラスに対してコンストラクターが明示的に定義されていない場合。この暗黙的に宣言された既定のコンストラクターは、空の本体で定義された既定のコンストラクターと同等です。(注: いくつかのコンストラクターが定義されているが、それらがすべてデフォルトでない場合、コンパイラーはデフォルトのコンストラクターを暗黙的に定義しません。これは、クラスのデフォルトのコンストラクターが存在しない可能性があることを意味します。)