web-dev-qa-db-ja.com

エラー:基本クラスコンストラクターは親クラスコンストラクターを明示的に初期化する必要があります

私はc ++が初めてです。以下のコードをコンパイルしようとすると、このエラーが発生します

constructor for 'child' must explicitly initialize the base class 'parent' which does not have a default constructor child::child(int a) {

こちらが私のクラスです

#include<iostream>
using namespace std;

class parent
{   
public :
    int x;
    parent(int a);
    int getX();
};

parent::parent(int a)
{
    x = a;
}

int parent::getX() 
{
    return x;
}

class child : public parent
{
public:
    child(int a);   
};

child::child(int a) 
{
    x = a;
}

int main(int n , char *argv[]) 
{

}

なぜこのエラーが発生するのですか?どうすれば解決できますか?前もって感謝します

25
charlotte

親クラスには明示的なコンストラクターがあるため、コンパイラーは暗黙的な「空の」コンストラクターを追加しません。さらに、コンストラクターにはパラメーターがあるため、コンパイラーは暗黙的な呼び出しを生成できません。そのため、明示的に行う必要があります。

こちらです:

 child::child(int a) : parent(a)
 {
 }
32
CiaPan

派生クラスのオブジェクトを初期化するときは、最初に基本クラスの部分を構築する必要があります。コンストラクターの1つを呼び出して、派生クラスのコンストラクターで自分で初期化しない場合、コンパイラーは基本クラスの既定のコンストラクターを使用しようとします。あなたの場合、カスタムコンストラクタをすでに提供しているため、デフォルトのコンストラクタは定義されていません。

これを解決するには、基本クラスのデフォルトコンストラクターを提供するか、派生クラスのコンストラクターの初期化リストでコンストラクターを呼び出す必要があります。

child::child(int a) : parent(a)
 {
 }
14
Veritas

エラーメッセージが繰り返し表示される危険があります。子クラスコンストラクターは、親のコンストラクターを呼び出す必要があります。

コンパイラーは、親のデフォルト(引数なし)コンストラクターの自動呼び出しを追加します。親にデフォルトのコンストラクターがない場合は、自分が持っているコンストラクターの1つを明示的に呼び出す必要があります。

コンパイラはこれを実施して、子クラスが親から継承した機能が正しく設定されるようにします。たとえば、子が親から継承したが直接アクセスできないプライベート変数を初期化します。クラスにはこの問題はありませんが、ルールに従う必要があります。

継承を使用するクラスのコンストラクターの例を次に示します。

これは問題ありません。ParentAにはデフォルトのコンストラクタがあります。

class ParentA
{
};

class ChildA
{
public:
    ChildA() {}
};

これは問題ありません。 ParentBにはデフォルトのコンストラクタがないため、ChildB1クラスはコンストラクタ自体のいずれかを明示的に呼び出す必要があります。

class ParentB
{
    int m_a;

public:
    ParentB(int a) : m_a(a) {}
};

class ChildB1 : public ParentB
{
    float m_b;

public:
    // You'll get an error like this here:
    // "error: no matching function for call to ‘ParentB::ParentB()’"
    ChildB1 (float b) : m_b(b) {}
};

これは問題ありません。ParentBのコンストラクタを明示的に呼び出しています。

class ChildB2 : public ParentB
{
    float m_b;

public:
    ChildB2(int a, float b) : ParentB(a), m_b(b) {}
};

これは問題ありません。ParentCには、自動的に呼び出されるデフォルトのコンストラクタがあります。

class ParentC
{
    int m_a;

public:
    ParentC() : m_a(0) {}
    ParentC(int a) : m_a(a) {}
};

class ChildC: public ParentC
{
    float m_b;

public:
    ChildC(float b) : m_b(b) {}
};
3
Rook

MyBookクラスが基本クラスBookから派生している別の例。 2つの引数を持つカスタムコンストラクターが基本クラスコンストラクターに提供されるようになったため、基本クラスのデフォルトコンストラクターはありません。メイン関数内では、派生クラスオブジェクトの新規が作成されます。最初に、コンパイラは存在しない基本クラスコンストラクターの呼び出しを試みます。そのため、派生クラスが基本クラスから継承したが直接アクセスできないプライベート変数(タイトル文字列変数など)を初期化するには、基本クラスコンストラクターを派生クラスコンストラクターから明示的に呼び出す必要があります。ユーザー rook が言及されているため、これらのルールに従う必要があります。 Alex Allain による 初期化リスト のニースの説明から、より詳細な情報を取得できます。そのため、定義済みのdafaultコンストラクターがない場合、および定数メンバーを初期化するためにも、初期化リストが必要です。彼は要約する

コンストラクターの本体が実行される前に、その親クラスとそのフィールドのすべてのコンストラクターが呼び出されます。デフォルトでは、引数なしのコンストラクターが呼び出されます。初期化リストを使用すると、呼び出されるコンストラクターと、コンストラクターが受け取る引数を選択できます。

#include <iostream>
#include <cstdio>

using namespace std;

class Book {
private:
    string title;
protected:
    string author;
public:
    Book(string t, string a) {
        title = t;
        author = a;
    };
    virtual void display() = 0;
};

class MyBook : public Book {
private:
        const string className;
protected:
        int price;
public:
        // Book(t,a) needs to be called before the {} block to initialize, otherwise error (does not match to Book::Book() default constructor will occur)         
        MyBook(string t, string a, int p) : Book(t, a), className("MyClass"), price(p){
        };

        void display() {
            cout << "Title: " << getTitle() << endl;
            cout << "Author: " << author << endl;
            cout << "Price: " << price << endl;
        };
};

int main() {
    string title, author;
    int price;
    getline(cin, title);
    getline(cin, author);
    cin >> price;
    MyBook novel(title, author, price);
    novel.display();

    return 0;
}
2
Ananda