18

クラスを継承していて、そのコンストラクターの 1 つを呼び出したいと考えています。ただし、それを呼び出す前に、いくつかのもの (基本クラスを必要としないもの) を処理する必要があります。初期化子リストで呼び出す代わりに、後で呼び出す方法はありますか? これは Java と C# で実行できると思いますが、C++ についてはわかりません。

コンストラクターに渡す必要があるデータは後で再割り当てできないため、既定のコンストラクターを呼び出して後で初期化することはできません。

4

6 に答える 6

32

初期化子リストで呼び出す代わりに、後で呼び出す方法はありますか?

いいえ、あなたがすることはできません。基本クラスのコンストラクターは初期化子リストで呼び出す必要があり、最初に呼び出す必要があります。

実際、そこで省略した場合、コンパイラは呼び出しを暗黙的に追加するだけです。

これは Java と C# で実行できると思いますが、C++ についてはわかりません。

C# も Java もこれを許可しません。

ただし、できることは、基本クラスのコンストラクター呼び出しの引数としてメソッドを呼び出すことですこれは、コンストラクターの前に処理されます。

class Derived {
public:
    Derived() : Base(some_function()) { }

private:
    static int some_function() { return 42; }
};
于 2010-09-29T11:19:06.087 に答える
14

何人かの回答者が言ったように、基本クラスコンストラクターの呼び出しを遅らせることはできませんが、Konradはあなたの問題をうまく解決するかもしれない良い答えを与えました。ただし、これには欠点があります(たとえば、計算が中間結果を共有する値で複数の関数を初期化する必要がある場合)。完全を期すために、これを使用して初期化順序が固定されている問題を解決する別の方法を示します。

初期化の順序が固定されている場合、派生クラスを制御できる場合(および、他にどのようにしてそのctorの1つをいじるのですか?)、プライベートベースに忍び込んで、他のクラスよりも先に初期化されるようにすることができます。ベース。これは、プライベートベースのすでに計算された値で初期化できます。

class my_dirty_little_secret {
  // friend class the_class;
public: 
  my_dirty_little_secret(const std::string& str)
  {
    // however that calculates x, y, and z from str I wouldn't know
  }
  int x;
  std::string y;
  float z;
};

class the_class : private my_dirty_little_secret // must be first, see ctor
                , public the_other_base_class {
  public:
    the_class(const std::string str)
      : my_dirty_little_secret(str)
      , the_other_base_class(x, y, z)
    {
    }
  // ...
};

このmy_dirty_little_secretクラスはプライベートベースであるため、ユーザーはthe_class使用できません。また、すべてのクラスはプライベートであり、明示的な友情により、クラスへのthe_classアクセスのみが許可されます。ただし、基本クラスリストの最初にリストされているthe_other_base_classため、の前に確実に構築され、計算したものを使用して初期化できます。
基本クラスリストでの素晴らしいコメントは、他の人がリファクタリングによって物事を壊すことを防ぐことができれば幸いです。

于 2010-09-29T12:57:09.450 に答える
0

うわー、私たちは皆かつて若かった。この答えはうまくいかないので、使用しないでください。コンテンツは歴史的な目的のために残されました。

基本クラスを完全に制御できる場合は、保護されたメソッドを追加してクラスの初期化を行い、仮想化し、派生クラスの実装の詳細をそのベースを呼び出す前に配置することをお勧めします。

class Base
{
public:
    Base()
    {
        Initialize();
    }
protected:
    virtual void Initialize()
    {
        //do initialization;
    }
};

class Derived : Base
{
public:

    Derived() : Base()
    {
    }
protected:
    virtual void Initialize()
    {
        //Do my initialization
        //call base
        Base::Initialize();
    }
};
于 2010-09-29T11:24:39.160 に答える
0

私見あなたが言及した方法で基本クラスコンストラクターの呼び出しを延期することは可能だとは思いません。

于 2010-09-29T11:21:11.403 に答える
-2
struct base{
   base(int x){}
};

struct derived : base{
   derived(int x) : base(x){}
};

これは、派生クラスの初期化リストから C++ で基底クラスのコンストラクターを呼び出す方法です。

于 2010-09-29T11:19:13.903 に答える