[C++] 派生クラスで親クラスの引数付きコンストラクタを呼ぶ方法

C++では、派生クラスのコンストラクタで親クラスの引数付きコンストラクタを呼び出すには、初期化リストを使用します。

派生クラスのコンストラクタの定義で、コロン : の後に親クラスのコンストラクタを呼び出す形で記述します。

例えば、Baseクラスの引数付きコンストラクタを Derivedクラスから呼び出す場合、Derived のコンストラクタで Base(arg) のように記述します。

これにより、親クラスのコンストラクタが適切に初期化されます。

この記事でわかること
  • 親クラスの引数付きコンストラクタの呼び方
  • 派生クラスでの初期化リストの使い方
  • 多重継承や仮想継承の注意点
  • テンプレートクラスの継承方法
  • 抽象クラスのコンストラクタの扱い方

目次から探す

親クラスの引数付きコンストラクタを呼ぶ方法

C++において、派生クラスが親クラスの引数付きコンストラクタを呼ぶ方法は、オブジェクトの初期化において非常に重要です。

これにより、親クラスの状態を適切に設定し、派生クラスの機能を正しく動作させることができます。

以下では、具体的な方法や理由について詳しく解説します。

初期化リストの基本構文

C++では、コンストラクタの初期化リストを使用して、親クラスのコンストラクタを呼び出します。

初期化リストは、コンストラクタの本体が始まる前に、メンバ変数を初期化するための構文です。

基本的な構文は以下の通りです。

ClassName(parameters) : ParentClassName(arguments) {
    // コンストラクタの本体
}

この構文を使用することで、親クラスのコンストラクタに引数を渡すことができます。

親クラスの引数付きコンストラクタを呼ぶ理由

親クラスの引数付きコンストラクタを呼ぶ理由は以下の通りです。

スクロールできます
理由説明
状態の初期化親クラスのメンバ変数を適切に初期化するため。
継承の一貫性派生クラスが親クラスの機能を正しく引き継ぐため。
コードの再利用性親クラスのロジックを再利用することで、冗長性を減らすため。

派生クラスのコンストラクタでの親クラスの初期化

派生クラスのコンストラクタで親クラスの引数付きコンストラクタを呼ぶ例を示します。

以下のコードでは、Baseクラスの引数付きコンストラクタをDerivedクラスから呼び出しています。

#include <iostream>
using namespace std;
class Base {
public:
    Base(int value) {
        cout << "Baseクラスのコンストラクタ: " << value << endl;
    }
};
class Derived : public Base {
public:
    Derived(int value) : Base(value) { // 親クラスのコンストラクタを呼ぶ
        cout << "Derivedクラスのコンストラクタ" << endl;
    }
};
int main() {
    Derived obj(10); // Derivedクラスのオブジェクトを生成
    return 0;
}
Baseクラスのコンストラクタ: 10
Derivedクラスのコンストラクタ

この例では、DerivedクラスのコンストラクタがBaseクラスのコンストラクタを呼び出し、引数を渡しています。

複数の引数を持つコンストラクタの呼び出し

親クラスが複数の引数を持つコンストラクタを持つ場合も、初期化リストを使用して呼び出すことができます。

以下のコードでは、Baseクラスのコンストラクタに2つの引数を渡しています。

#include <iostream>
using namespace std;
class Base {
public:
    Base(int a, int b) {
        cout << "Baseクラスのコンストラクタ: " << a << ", " << b << endl;
    }
};
class Derived : public Base {
public:
    Derived(int a, int b) : Base(a, b) { // 複数の引数を親クラスに渡す
        cout << "Derivedクラスのコンストラクタ" << endl;
    }
};
int main() {
    Derived obj(5, 10); // Derivedクラスのオブジェクトを生成
    return 0;
}
Baseクラスのコンストラクタ: 5, 10
Derivedクラスのコンストラクタ

デフォルトコンストラクタがない場合の対応

親クラスにデフォルトコンストラクタが存在しない場合、派生クラスのコンストラクタは必ず親クラスの引数付きコンストラクタを呼ぶ必要があります。

デフォルトコンストラクタがないと、親クラスの初期化が行われず、コンパイルエラーが発生します。

以下のコードはその例です。

#include <iostream>
using namespace std;
class Base {
public:
    Base(int value) { // デフォルトコンストラクタがない
        cout << "Baseクラスのコンストラクタ: " << value << endl;
    }
};
class Derived : public Base {
public:
    Derived(int value) : Base(value) { // 親クラスのコンストラクタを呼ぶ
        cout << "Derivedクラスのコンストラクタ" << endl;
    }
};
int main() {
    Derived obj(20); // Derivedクラスのオブジェクトを生成
    return 0;
}
Baseクラスのコンストラクタ: 20
Derivedクラスのコンストラクタ

このように、親クラスにデフォルトコンストラクタがない場合でも、引数付きコンストラクタを正しく呼び出すことで、オブジェクトを正常に初期化できます。

実際のコード例

ここでは、親クラスの引数付きコンストラクタを呼ぶ具体的なコード例を示します。

これにより、実際のプログラミングにおける使い方を理解しやすくします。

単一の引数を持つ親クラスのコンストラクタを呼ぶ例

以下のコードでは、親クラスBaseが単一の引数を持つコンストラクタを持ち、派生クラスDerivedからそのコンストラクタを呼び出しています。

#include <iostream>
using namespace std;
class Base {
public:
    Base(int value) {
        cout << "Baseクラスのコンストラクタ: " << value << endl;
    }
};
class Derived : public Base {
public:
    Derived(int value) : Base(value) { // 親クラスのコンストラクタを呼ぶ
        cout << "Derivedクラスのコンストラクタ" << endl;
    }
};
int main() {
    Derived obj(42); // Derivedクラスのオブジェクトを生成
    return 0;
}
Baseクラスのコンストラクタ: 42
Derivedクラスのコンストラクタ

この例では、DerivedクラスのコンストラクタがBaseクラスのコンストラクタを呼び出し、引数を渡しています。

複数の引数を持つ親クラスのコンストラクタを呼ぶ例

次に、親クラスが複数の引数を持つコンストラクタを持つ場合の例を示します。

#include <iostream>
using namespace std;
class Base {
public:
    Base(int a, int b) {
        cout << "Baseクラスのコンストラクタ: " << a << ", " << b << endl;
    }
};
class Derived : public Base {
public:
    Derived(int a, int b) : Base(a, b) { // 複数の引数を親クラスに渡す
        cout << "Derivedクラスのコンストラクタ" << endl;
    }
};
int main() {
    Derived obj(5, 10); // Derivedクラスのオブジェクトを生成
    return 0;
}
Baseクラスのコンストラクタ: 5, 10
Derivedクラスのコンストラクタ

この例では、Derivedクラスのコンストラクタが2つの引数をBaseクラスに渡しています。

親クラスのデフォルトコンストラクタと引数付きコンストラクタの両方を持つ場合

親クラスがデフォルトコンストラクタと引数付きコンストラクタの両方を持つ場合の例を示します。

#include <iostream>
using namespace std;
class Base {
public:
    Base() {
        cout << "Baseクラスのデフォルトコンストラクタ" << endl;
    }
    Base(int value) {
        cout << "Baseクラスの引数付きコンストラクタ: " << value << endl;
    }
};
class Derived : public Base {
public:
    Derived() : Base() { // デフォルトコンストラクタを呼ぶ
        cout << "Derivedクラスのデフォルトコンストラクタ" << endl;
    }
    Derived(int value) : Base(value) { // 引数付きコンストラクタを呼ぶ
        cout << "Derivedクラスの引数付きコンストラクタ" << endl;
    }
};
int main() {
    Derived obj1; // デフォルトコンストラクタを使用
    Derived obj2(20); // 引数付きコンストラクタを使用
    return 0;
}
Baseクラスのデフォルトコンストラクタ
Derivedクラスのデフォルトコンストラクタ
Baseクラスの引数付きコンストラクタ: 20
Derivedクラスの引数付きコンストラクタ

この例では、Derivedクラスが親クラスのデフォルトコンストラクタと引数付きコンストラクタの両方を呼び出しています。

派生クラスで独自のメンバ変数を初期化する場合

派生クラスで独自のメンバ変数を初期化する場合の例を示します。

親クラスのコンストラクタを呼び出しつつ、派生クラスのメンバ変数も初期化します。

#include <iostream>
using namespace std;
class Base {
public:
    Base(int value) {
        cout << "Baseクラスのコンストラクタ: " << value << endl;
    }
};
class Derived : public Base {
private:
    int derivedValue;
public:
    Derived(int baseValue, int derivedValue) : Base(baseValue), derivedValue(derivedValue) { // 親クラスのコンストラクタを呼ぶ
        cout << "Derivedクラスのコンストラクタ: " << derivedValue << endl;
    }
};
int main() {
    Derived obj(30, 50); // Derivedクラスのオブジェクトを生成
    return 0;
}
Baseクラスのコンストラクタ: 30
Derivedクラスのコンストラクタ: 50

この例では、Derivedクラスのコンストラクタが親クラスのコンストラクタを呼び出し、さらに独自のメンバ変数derivedValueを初期化しています。

応用例

C++では、さまざまな継承の形態があり、それぞれにおいて親クラスのコンストラクタを呼び出す方法が異なります。

以下では、いくつかの応用例を示します。

多重継承時の親クラスのコンストラクタ呼び出し

多重継承では、複数の親クラスから派生クラスを作成することができます。

この場合、各親クラスのコンストラクタを適切に呼び出す必要があります。

以下の例では、Base1Base2の2つの親クラスを持つDerivedクラスを示します。

#include <iostream>
using namespace std;
class Base1 {
public:
    Base1(int value) {
        cout << "Base1クラスのコンストラクタ: " << value << endl;
    }
};
class Base2 {
public:
    Base2(int value) {
        cout << "Base2クラスのコンストラクタ: " << value << endl;
    }
};
class Derived : public Base1, public Base2 {
public:
    Derived(int value1, int value2) : Base1(value1), Base2(value2) { // 各親クラスのコンストラクタを呼ぶ
        cout << "Derivedクラスのコンストラクタ" << endl;
    }
};
int main() {
    Derived obj(10, 20); // Derivedクラスのオブジェクトを生成
    return 0;
}
Base1クラスのコンストラクタ: 10
Base2クラスのコンストラクタ: 20
Derivedクラスのコンストラクタ

この例では、Derivedクラスが2つの親クラスのコンストラクタを呼び出しています。

仮想継承時のコンストラクタ呼び出し

仮想継承を使用する場合、親クラスのコンストラクタは派生クラスのコンストラクタから直接呼び出す必要があります。

以下の例では、Baseクラスを仮想基底クラスとして使用しています。

#include <iostream>
using namespace std;
class Base {
public:
    Base(int value) {
        cout << "Baseクラスのコンストラクタ: " << value << endl;
    }
};
class Derived1 : virtual public Base {
public:
    Derived1(int value) : Base(value) { // 親クラスのコンストラクタを呼ぶ
        cout << "Derived1クラスのコンストラクタ" << endl;
    }
};
class Derived2 : virtual public Base {
public:
    Derived2(int value) : Base(value) { // 親クラスのコンストラクタを呼ぶ
        cout << "Derived2クラスのコンストラクタ" << endl;
    }
};
class FinalDerived : public Derived1, public Derived2 {
public:
    FinalDerived(int value) : Base(value), Derived1(value), Derived2(value) { // Baseのコンストラクタを呼ぶ
        cout << "FinalDerivedクラスのコンストラクタ" << endl;
    }
};
int main() {
    FinalDerived obj(30); // FinalDerivedクラスのオブジェクトを生成
    return 0;
}
Baseクラスのコンストラクタ: 30
Derived1クラスのコンストラクタ
Derived2クラスのコンストラクタ
FinalDerivedクラスのコンストラクタ

この例では、FinalDerivedクラスBaseクラスのコンストラクタを呼び出しています。

仮想継承を使用することで、Baseクラスのインスタンスが一度だけ生成されます。

テンプレートクラスを継承する場合のコンストラクタ呼び出し

テンプレートクラスを継承する場合も、親クラスのコンストラクタを呼び出すことができます。

以下の例では、テンプレートクラスBaseを継承したDerivedクラスを示します。

#include <iostream>
using namespace std;
template <typename T>
class Base {
public:
    Base(T value) {
        cout << "Baseクラスのコンストラクタ: " << value << endl;
    }
};
class Derived : public Base<int> { // int型のBaseクラスを継承
public:
    Derived(int value) : Base(value) { // 親クラスのコンストラクタを呼ぶ
        cout << "Derivedクラスのコンストラクタ" << endl;
    }
};
int main() {
    Derived obj(100); // Derivedクラスのオブジェクトを生成
    return 0;
}
Baseクラスのコンストラクタ: 100
Derivedクラスのコンストラクタ

この例では、DerivedクラスBase<int>のコンストラクタを呼び出しています。

テンプレートを使用することで、柔軟なクラス設計が可能になります。

親クラスが抽象クラスの場合のコンストラクタ呼び出し

親クラスが抽象クラスの場合でも、コンストラクタを呼び出すことができます。

抽象クラスは純粋仮想関数を持つクラスであり、直接インスタンス化することはできませんが、派生クラスでそのコンストラクタを呼び出すことができます。

以下の例を示します。

#include <iostream>
using namespace std;
class AbstractBase {
public:
    AbstractBase(int value) {
        cout << "AbstractBaseクラスのコンストラクタ: " << value << endl;
    }
    virtual void show() = 0; // 純粋仮想関数
};
class Derived : public AbstractBase {
public:
    Derived(int value) : AbstractBase(value) { // 親クラスのコンストラクタを呼ぶ
        cout << "Derivedクラスのコンストラクタ" << endl;
    }
    void show() override { // 純粋仮想関数の実装
        cout << "Derivedクラスのshow関数" << endl;
    }
};
int main() {
    Derived obj(50); // Derivedクラスのオブジェクトを生成
    obj.show(); // show関数を呼び出す
    return 0;
}
AbstractBaseクラスのコンストラクタ: 50
Derivedクラスのコンストラクタ
Derivedクラスのshow関数

この例では、DerivedクラスAbstractBaseクラスのコンストラクタを呼び出し、純粋仮想関数showを実装しています。

抽象クラスを使用することで、インターフェースを定義し、派生クラスで具体的な実装を行うことができます。

よくある質問

親クラスのコンストラクタを呼ばないとどうなる?

親クラスのコンストラクタを呼ばない場合、以下のような問題が発生します。

  • 未初期化の状態: 親クラスのメンバ変数が初期化されないため、未定義の状態になる可能性があります。
  • コンパイルエラー: 親クラスにデフォルトコンストラクタが存在しない場合、派生クラスのコンストラクタで親クラスのコンストラクタを呼ばないと、コンパイルエラーが発生します。
  • プログラムの不具合: 親クラスの初期化が行われないため、プログラムの動作が不安定になり、予期しない動作を引き起こすことがあります。

派生クラスで親クラスのデフォルトコンストラクタを呼ぶには?

派生クラスで親クラスのデフォルトコンストラクタを呼ぶには、初期化リストを使用します。

以下のように記述します。

class Derived : public Base {
public:
    Derived() : Base() { // 親クラスのデフォルトコンストラクタを呼ぶ
        // 派生クラスの初期化処理
    }
};

このようにすることで、親クラスのデフォルトコンストラクタが呼ばれ、親クラスのメンバ変数が適切に初期化されます。

親クラスのコンストラクタにデフォルト引数がある場合、どう扱う?

親クラスのコンストラクタにデフォルト引数がある場合、派生クラスのコンストラクタからその引数を省略することができます。

以下のように記述します。

class Base {
public:
    Base(int value = 0) { // デフォルト引数を持つコンストラクタ
        // 初期化処理
    }
};
class Derived : public Base {
public:
    Derived() : Base() { // デフォルト引数を使用して親クラスのコンストラクタを呼ぶ
        // 派生クラスの初期化処理
    }
};

この場合、DerivedクラスのコンストラクタでBase()と記述することで、デフォルト引数が適用され、親クラスのコンストラクタが呼ばれます。

必要に応じて、引数を指定することも可能です。

まとめ

この記事では、C++における派生クラスで親クラスの引数付きコンストラクタを呼ぶ方法について詳しく解説しました。

具体的なコード例を通じて、単一および複数の引数を持つコンストラクタの呼び出し方や、多重継承、仮想継承、テンプレートクラス、抽象クラスにおけるコンストラクタの扱いについても触れました。

これらの知識を活用して、より効果的なクラス設計を行い、C++プログラミングのスキルを向上させてみてください。

当サイトはリンクフリーです。出典元を明記していただければ、ご自由に引用していただいて構いません。

関連カテゴリーから探す

  • URLをコピーしました!
目次から探す