web-dev-qa-db-ja.com

基本クラスコンストラクターを呼び出す方法

latley私はJavaで多くのプログラミングをしました。そこで、super();を使用して、継承元のクラスを呼び出します(おそらくすべて知っています)。

これで、いくつかの引数を取るデフォルトのコンストラクタを持つC++のクラスができました。例:

class BaseClass {
public:
    BaseClass(char *name); .... 

クラスを継承すると、適切なデフォルトコンストラクターがないという警告が表示されます。 C++にはsuper()のようなものがありますか、それともすべての変数を初期化する関数を定義する必要がありますか?

62
Stefan

これは、サブクラスのコンストラクターの初期化リストで行います。

class Foo : public BaseClass {
public:
    Foo() : BaseClass("asdf") {}
};

引数を取る基本クラスコンストラクターは、メンバーが初期化される前にそこで呼び出される必要があります。

81
Björn Pollex

ヘッダーファイルで基本クラスを定義します。

class BaseClass {
public:
    BaseClass(params);
};

次に、派生クラスをBaseClassを継承するように定義します。

class DerivedClass : public BaseClass {
public:
    DerivedClass(params);
};

ソースファイルでBaseClassコンストラクターを定義します。

BaseClass::BaseClass(params)
{
     //Perform BaseClass initialization
}

デフォルトでは、派生コンストラクターは、パラメーターなしでデフォルトの基本コンストラクターのみを呼び出します。そのため、この例では、派生コンストラクターが呼び出されたときに基本クラスコンストラクターは自動的に呼び出されませんが、コロン(:)の後に基本クラスコンストラクター構文を追加するだけで実現できます。ベースコンストラクターを自動的に呼び出す派生コンストラクターを定義します。

DerivedClass::DerivedClass(params) : BaseClass(params)
{
     //This occurs AFTER BaseClass(params) is called first and can
     //perform additional initialization for the derived class
}

BaseClassコンストラクターはDerivedClassコンストラクターの前に呼び出され、必要に応じて同じ/異なるパラメーターparamsを基本クラスに転送できます。これは、より深い派生クラスのためにネストできます。派生コンストラクターは、EXACTLY ONEベースコンストラクターを呼び出す必要があります。デストラクタは、コンストラクタが呼び出された逆順で自動的に呼び出されます。

編集:virtualクラスから継承する場合、通常は多重継承またはdiamond inheritance。次に、すべてのvirtual基本クラスの基本コンストラクターを明示的に呼び出してパラメーターを明示的に渡す必要があります。そうでない場合は、デフォルトコンストラクターwithoutのみを呼び出します任意のパラメーター。参照: 仮想継承-コンストラクターのスキップ

28
MasterHD

イニシエーターを使用する必要があります。

class DerivedClass : public BaseClass
{
public:
  DerivedClass()
    : BaseClass(<insert arguments here>)
  {
  }
};

これは、コンストラクターを持たない(または初期化する)クラスのメンバーを構築する方法でもあります。言及されていないメンバーはデフォルトで初期化されます。例えば:

class DerivedClass : public BaseClass
{
public:
  DerivedClass()
    : BaseClass(<insert arguments here>)
    , nc(<insert arguments here>)
    //di will be default initialized.
  {
  }

private:
  NeedsConstructor nc;
  CanBeDefaultInit di;
};

メンバーが指定される順序は関係ありません(ただし、コンストラクターが最初に来る必要があります)が、メンバーが構成される順序は宣言の順序になります。したがって、ncは常にdiの前に構築されます。

17
Nicol Bolas

スーパーの代替案について;ほとんどの場合、派生クラスの初期化リストで基本クラスを使用するか、他の場所で作業を行って派生クラスがデータメンバーを再定義するときにBase::someData構文を使用します。

struct Base
{
    Base(char* name) { }
    virtual ~Base();
    int d;
};

struct Derived : Base
{
    Derived() : Base("someString") { }
    int d;
    void foo() { d = Base::d; }
};
4
Seb Holzapfel

初期化リストで基本クラスの名前を使用します。 initializer-listは、コンストラクターシグネチャの後にメソッド本体の前に表示され、基本クラスとメンバーを初期化するために使用できます。

class Base
{
public:
  Base(char* name)
  {
     // ...
  }
};

class Derived : Base
{
public:
  Derived()
    : Base("hello")
  {
      // ...
  }
};

または、一部の人々が使用するパターンは、「スーパー」または「ベース」を自分で定義することです。おそらく、この手法を好む人の中には、C++に移行しているJava開発者がいます。

class Derived : Base
{
public:
  typedef Base super;
  Derived()
    : super("hello")
  {
      // ...
  }
};
3
Scott Langham

C++にはsuper()はありません。基本コンストラクタを名前で明示的に呼び出す必要があります。

2
Shamim Hafiz