©️

C++ コンストラクタ・デストラクタ

2024/10/08に公開

コンストラクタ・デストラクタ

コンストラクタ

  • オブジェクトが生成されるときに自動的に呼び出される特別な関数
  • 初期化を行うために使用

デフォルトコンストラクタ

  • 引数を持たないコンストラクタ

暗黙のデフォルトコンストラクタ

  • 明示的にコンストラクタを定義しない場合、コンパイラが自動的に生成する

コピーコンストラクタ

  • 既存のオブジェクトをもとに新しいオブジェクトを初期化するためのコンストラクタ
  • 明示的にコピーコンストラクタを定義しない場合、コンパイラが自動的に生成する
  • デフォルトのコピーコンストラクタは、メンバ変数の浅いコピーを行う
    動的に確保されたメモリやポインタは複製されないため、複数のオブジェクトが同じメモリを共有してしまう

デストラクタ

  • オブジェクトが破棄される際に自動的に呼び出される特別なメンバ関数
  • オブジェクトが動的に確保したメモリや、開いたファイルなど、特別なリソースを管理している場合は、明示的にデストラクタを定義する必要があり、リソースを解放する処理を実行する
  • 引数をとることができない

暗黙のデフォルトデストラクタ

  • プログラマーが明示的にデストラクタを定義していない場合、コンパイラーが自動的に生成するデストラクタ

サンプルコード

#include <iostream>

class Base {
public:
    // デフォルトコンストラクタ
    Base() {
        std::cout << "基底クラス デフォルトコンストラクタ" << std::endl;
        base_number_ = new int(0);
    }
    // コンストラクタ
    Base(int base_num) {
        std::cout << "基底クラス コンストラクタ" << std::endl;
        base_number_ = new int(base_num);
    }
    // コピーコンストラクタ
    Base(const Base &source) {
        std::cout << "基底クラス コピーコンストラクタ" << std::endl;
        base_number_ = new int(*source.base_number_);
    }
    // デストラクタ
    ~Base() {
        std::cout << "基底クラス デストラクタ" << std::endl;
        delete base_number_;
    }
    void baseFunc() {
        std::cout << "基底クラスの関数 " << "base_number_: " << *base_number_ << std::endl;
    }

private:
    int* base_number_;
};

class Derived : public Base {
public:
    // デフォルトコンストラクタ
    Derived() {
        std::cout << "派生クラス デフォルトコンストラクタ" << std::endl;
        derived_number_ = 0;
    }
    // コンストラクタ(引数1つ)
    Derived(int derived_num) : derived_number_(derived_num) {
        std::cout << "派生クラス コンストラクタ (1) " << std::endl;
    }
    // コンストラクタ(引数2つ、オーバーロード)
    Derived(int base_num, int derived_num) : Base(base_num), derived_number_(derived_num) {
        std::cout << "派生クラス コンストラクタ (2) " << std::endl;
    }
    // コピーコンストラクタ
    Derived(const Derived& source) : Base(source) {
        std::cout << "派生クラス コピーコンストラクタ" << std::endl;
        derived_number_ = source.derived_number_;
    }
    // デストラクタ
    ~Derived() {
        std::cout << "派生クラス デストラクタ" << std::endl;
        derived_number_ = -1;
    }
    void derivedFunc() {
        std::cout << "派生クラスの関数 " << "derived_number_: " << derived_number_ << std::endl;
    }

private:
    int derived_number_;
};

int main() {
    do {
        std::cout << "------------------------------" << std::endl;
        // デフォルトコンストラクタ
        Derived derived;
        derived.baseFunc();
        derived.derivedFunc();
    } while(0);

    do {
        std::cout << "------------------------------" << std::endl;
        // コンストラクタ
        Derived derived(1);
        derived.baseFunc();
        derived.derivedFunc();
    } while(0);

    do {
        std::cout << "------------------------------" << std::endl;
        // コピーコンストラクタ
        Derived derived1(2, 3);
        Derived derived2 = derived1;
        derived2.baseFunc();
        derived2.derivedFunc();
    } while(0);
}

実行結果

------------------------------
基底クラス デフォルトコンストラクタ
派生クラス デフォルトコンストラクタ
基底クラスの関数 base_number_: 0
派生クラスの関数 derived_num_: 0
派生クラス デストラクタ
基底クラス デストラクタ
------------------------------
基底クラス デフォルトコンストラクタ
派生クラス コンストラクタ (1) 
基底クラスの関数 base_number_: 0
派生クラスの関数 derived_num_: 1
派生クラス デストラクタ
基底クラス デストラクタ
------------------------------
基底クラス コンストラクタ
派生クラス コンストラクタ (2) 
基底クラス コピーコンストラクタ
派生クラス コピーコンストラクタ
基底クラスの関数 base_number_: 2
派生クラスの関数 derived_num_: 3
派生クラス デストラクタ
基底クラス デストラクタ
派生クラス デストラクタ
基底クラス デストラクタ

Discussion