データや関数を含むクラスの内部構造は複雑なので、
オブジェクトの初期化やクラス終結処理は、単純なデータ構造の場合より格段に複雑です。
コンストラクターやデストラクターは、クラス・オブジェクトの構成や
破棄に使用されるクラスの特殊なメンバー関数です。構成では、オブジェクトのメモリー割り振りや初期化もあわせて
行われる場合があります。破棄に際しては、オブジェクトのメモリーの終結処理や割り振り解除も
行われる場合があります。
他のメンバー関数と同様、コンストラクターとデストラクターは、クラス宣言の中で宣言されます。 これらは、インラインまたはクラス宣言の外で定義することができます。 コンストラクターは、デフォルトの引き数を持つことができます。 コンストラクターは、他のメンバー関数と異なり、メンバー初期化リストを持つことができます。 コンストラクターとデストラクターには、次の制約事項が適用されます。
コンストラクターとデストラクターは、メンバー関数と同じアクセス規則に従います。 例えば、protected を使用してコンストラクターを宣言した場合、 それを使用してクラス・オブジェクトを使用できるのは、派生クラスとフレンドだけです。
コンパイラーは、クラス・オブジェクトを定義するときはコンストラクターを、 クラス・オブジェクトがスコープ外に出るときはデストラクターを、それぞれ自動的に呼び出します。 コンストラクターは、その this ポインターが参照するクラス・オブジェクトに、 メモリーを割り振ることはありませんが、 そのクラス・オブジェクトが参照するオブジェクトより多くのオブジェクトに、ストレージを割り振る場合があります。 オブジェクトのためにメモリー割り振りが必要な場合、 コンストラクターは、明示的に new 演算子を呼び出します。 終結処理時に、デストラクターは、 対応するコンストラクターによって割り振られたオブジェクトを解放します。 オブジェクトを解放するには、delete 演算子を使用します。
派生クラスはその基底クラスのコンストラクターやデストラクターを継承しませんが、 基底クラスのコンストラクターやデストラクターを呼び出します。 デストラクターは、virtual というキーワードで宣言できます。
コンストラクターは、ローカルまたは一時クラス・オブジェクトが作成されるときにも呼び出され、 デストラクターは、ローカルまたは 一時オブジェクトがスコープを超えたときに呼び出されます。
コンストラクターまたはデストラクターから、メンバー関数を呼び出すことができます。 クラス A のコンストラクター、またはデストラクターから、 直接的に、あるいは間接的に仮想関数を呼び出すことができます。 この場合、呼び出される関数は A で定義されているものか、A の基底クラスであり、A から派生したクラスでオーバーライドされた関数ではありません。 これにより、コンストラクター、またはデストラクターから、非構成オブジェクトにアクセスする可能性を回避します。 次の例は、このことを示しています。
#include <iostream> using namespace std; struct A { virtual void f() { cout << "void A::f()" << endl; } virtual void g() { cout << "void A::g()" << endl; } virtual void h() { cout << "void A::h()" << endl; } }; struct B : A { virtual void f() { cout << "void B::f()" << endl; } B() { f(); g(); h(); } }; struct C : B { virtual void f() { cout << "void C::f()" << endl; } virtual void g() { cout << "void C::g()" << endl; } virtual void h() { cout << "void C::h()" << endl; } }; int main() { C obj; }
次に、上記の例の出力を示します。
void B::f() void A::g() void A::h()
例では obj いう名前で型 C のオブジェクトを作成しますが、B のコンストラクターは、C が B から派生しているので、C でオーバーライドされた関数は、どれも呼び出しません。
コンストラクター、またはデストラクターで typeid または dynamic_cast 演算子を使用でき、同様に、コンストラクターのメンバー初期化指定子も使用できます。
関連参照