派生クラスコンストラクターで基本クラスのメンバー変数を初期化するにはどうすればよいですか?


123

なぜこれができないのですか?

class A
{
public:
    int a, b;
};

class B : public A
{
    B() : A(), a(0), b(0)
    {
    }

};

7
あなたは求めているなぜあなたはそれを行うことができない言語設計の問題である、またはあなたが求めている、その言語の制限を回避するために?
ロブ・ケネディ

ベースコンストラクタを使用せずに、知らないうちに特別な方法があるのではないかと思いました。
amrhassan 2011

基本クラスのメンバーは、派生クラスのコンストラクターが実行される時点ですでに初期化されています。アクセス権がある場合それらを割り当てたり、セッターを呼び出したり、適切な場合はそれらの値を基本クラスコンストラクターに提供したりできます。考案されたクラスで実行できないことの1つは、それらを初期化することです。
ローン侯爵

回答:


143

これらはのメンバーではないため、初期化aおよびbを実行できません。これらはのメンバーであるため、初期化のみが可能です。それらを公開してからで割り当てを行うことができますが、カプセル化が破壊されるため、これは推奨されるオプションではありません。代わりに、中コンストラクタを作成できるようにする(または任意のサブクラスを、それらを初期化します):BBAABABA

class A 
{
protected:
    A(int a, int b) : a(a), b(b) {} // Accessible to derived classes
    // Change "protected" to "public" to allow others to instantiate A.
private:
    int a, b; // Keep these variables private in A
};

class B : public A 
{
public:
    B() : A(0, 0) // Calls A's constructor, initializing a and b in A to 0.
    {
    } 
};

32
あなたの例は正しいですが、あなたの説明は誤解を招くものです。それらがプライベートであるため、初期化 a内部化ができないということではありません。これらはのメンバーではないため、初期化できません。それらを公開または保護した場合は、の本文に割り当てることができます。bB::B()class BB::B()
R Samuel Klatchko、2011

2
さらに、あなたの解決策はクラスAを非集約にするため、重要になる可能性があるため、言及する必要があります。
Gene Bushuyev、2009

1
@R Samuel Klatchko:いいですね。回答を書いているとき、最初に「You ca n't access aand b...」と入力し、残りの文が意味をなさないことを確認せずに「You ca n't initialize ...」に変更しました。投稿を編集しました。
インシリコ2011年

1
@Gene Bushuyev:問題の元のコード内のクラスではない集計(非静的プライベートメンバーがあります)
デビッド・ロドリゲス- dribeas

@David-正しい、これはユーザーのエラーであり、私はユーザーの意図を理解しようとしていますが、表面的なものはスキップします。
Gene Bushuyev、2011

26

それらはprivateaありb、のメンバーであるためAA他のクラスのコンストラクター(派生または非派生)ではなく、のコンストラクターによって初期化されることを意図しています。

試してください:

class A
{
    int a, b;

protected: // or public:
    A(int a, int b): a(a), b(b) {}
};

class B : public A
{
    B() : A(0, 0) {}
};

7

どういうわけか、誰も最も簡単な方法を挙げていません:

class A
{
public:
    int a, b;
};

class B : public A
{
    B()
    {
        a = 0;
        b = 0;
    }

};

初期化子リスト内の基本メンバーにはアクセスできませんが、コンストラクター自体は、他のメンバーメソッドと同様に、基本クラスのpublicprotectedメンバーにアクセスできます。


1
いいね。この方法で欠点はありますか?
Wander3r

2
@SaileshD:コストのかかるコンストラクターを使用してオブジェクトを初期化している場合があります。のインスタンスBが割り当てられると、最初にデフォルトで初期化され、次にBコンストラクター内で割り当てられます。しかし、コンパイラーはこれを最適化できると私は思います。
バイオレットキリン

1
内部でclass Aab初期化に依存することはできません。class C : public Aたとえば、の実装では、呼び出しa=0;を忘れてa初期化されないままになる場合があります。
Sparkofska

@Sparkofska、とても本当です。フィールドを宣言するときにその場で(class A { int a = 0;};)、または基本クラスのコンストラクターでフィールドをデフォルトで初期化することをお勧めします。サブクラスは、必要に応じて、コンストラクターでサブクラスを再初期化できます。
バイオレットキリン

1
@ Wander3rもう1つの欠点は、すべてのクラスに代入演算子があるわけではないことです。一部は構築のみ可能で、割り当てはできません。その後、完了です...
マーティンペッカ

2
# include<stdio.h>
# include<iostream>
# include<conio.h>

using namespace std;

class Base{
    public:
        Base(int i, float f, double d): i(i), f(f), d(d)
        {
        }
    virtual void Show()=0;
    protected:
        int i;
        float f;
        double d;
};


class Derived: public Base{
    public:
        Derived(int i, float f, double d): Base( i, f, d)
        {
        }
        void Show()
        {
            cout<< "int i = "<<i<<endl<<"float f = "<<f<<endl <<"double d = "<<d<<endl;
        }
};

int main(){
    Base * b = new Derived(10, 1.2, 3.89);
    b->Show();
    return 0;
}

これは、Derivedクラスオブジェクトに存在するBaseクラスのデータメンバーを初期化し、Derivedクラスコンストラクター呼び出しを介してこれらの値をプッシュする場合の実用的な例です。


1

これはまれなケースでは便利ですが(そうでない場合は、言語で直接許可されていました)、メンバーイディオムのベースを確認してください。これはコードフリーのソリューションではありません。継承のレイヤーを追加する必要がありますが、それで仕事が完了します。ボイラープレートコードを回避するには、boostの実装を使用できます。


0

なんでできないの?この言語では、派生クラスの初期化子リストで基本クラスのメンバーを初期化することができないためです。

どうすればこれを達成できますか?このような:

class A
{
public:
    A(int a, int b) : a_(a), b_(b) {};
    int a_, b_;
};

class B : public A
{
public:
    B() : A(0,0) 
    {
    }
};

-1

クラスメンバーの可視性を指定しない場合、デフォルトで「プライベート」になります。サブクラスでメンバーにアクセスする場合は、メンバーをプライベートまたは保護する必要があります。


-1

example(*)のAのような集約クラスは、メンバーがパブリックでなければならず、ユーザー定義コンストラクターを持っていない必要があります。それらは、初期化リストで初期化さA a {0,0};れます(例:またはあなたの場合)B() : A({0,0}){}。基本集約クラスのメンバーは、派生クラスのコンストラクターで個別に初期化することはできません。

(*)正確に言うと、正しく言及されたように、オリジナルclass Aはプライベートな非静的メンバーのために集合体ではありません

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.