C++でメソッドの結果をパラメータとして基本クラスのコンストラクターに渡すにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/375141

質問

私は次のようなことを達成しようとしています:

class Base
{
  public:

  Base(string S) 
  {
  ...
  };
}

class Derived: Base
{
public:
  int foo;
  string bar()
  {
    return stringof(foo); // actually, something more complex
  };

  Derived(int f) : foo(f), Base(bar()) 
  {
  };
}

foo が初期化される前に、派生コンストラクターで bar() が呼び出されるため、これは期待どおりに動作しません。

foo をパラメータとして受け取る bar() に似た静的関数を追加し、それを初期化リストで使用することを検討しましたが、これを自分で掘り出すために使用できる他のテクニックがあるかどうか尋ねてみようと思いました。 ..

編集:フィードバックありがとうございます。静的関数をどのように処理するかは次のとおりです。静的関数と非静的関数の間のオーバーロードが賢すぎるかどうかはわかりませんが、...

class Derived: Base
{
public:
  int foo;

  static string bar(int f)
  {
    return stringof(f); // actually, something more complex
  }

  string bar()
  {
    return bar(foo); 
  };

  Derived(int f) :  Base(bar(f)) , foo(f)
  {
  };
}
役に立ちましたか?

解決

はい、パラメータとして FOO を取得し、文字列は良い解決策である返す関数を(静的クラスメソッドまたは通常の関数)を使用。あなたは、コードの重複を防ぐために派生::バーから、これと同じ機能を呼び出すことができます。だから、あなたのコンストラクタは次のようになります:

Derived(int f) : Base(stringof(f)), foo(f) {}

私は初期化が発生する順序を強調するために、リスト内の最初の基本コンストラクタに電話をかけます。すべてのクラスのメンバーは、彼らがクラス本体内で宣言された順序で初期化される初期化子リストの順序は効果がありません。

この問題に非常にきれいな、機能のアプローチです。あなたはまだ選択肢を比較検討したい場合は、その後の関係のために組成の代わりの継承を使用することを検討してください派生と基本クラスの間ます:

class Base {
public:
    Base(string S) {  ...  }
    void bat() { ... }
};

class Derived {
    Base *base;
    int foo;

public:
    Derived(int f) : base(NULL), foo(f) {
        base = new Base(bar());
    }
    ~Derived() {
        delete base;
    }

    string bar() {
        return stringof(foo); // actually, something more complex
    }

    void bat() {
        base->bat();
    }
};

あなたは<のhref = "http://blogs.msdn.com/steverowe/archive/2008/04/28/prefer-composition-over-inheritance.aspx" のrel = "nofollowをnoreferrer" を検討する必要があります。 >あなたの特定の状況に賛否両論と。ベースへの参照を保持している派生を使用すると、初期化の順序をより細かく制御を獲得します。

他のヒント

初期化子リストでは静的関数のみを呼び出すことができます。コードに含める方法は次のとおりです。

class Derived: Base
{
public:
  int foo;
  string bar()
  {
    return stringof(foo); // actually, something more complex
  };

  Derived(int f) : foo(f), Base(bar()) 
  {
  };
}

それでも最初に Base を初期化し、次に foo を初期化します。コンストラクター初期化子リストでの記述順序はまったく重要ではありません。常に次の順序で構築されます。

  1. まず、すべての仮想基本クラス
  2. 次に、非仮想基本クラスを基本クラス リストに表示される順序で並べます。
  3. 次に、すべてのメンバー オブジェクトがクラス定義で定義されている順序で表示されます。

したがって、最終的に電話をかけることになります stringof 初期化されていない値を持つ。この問題は次のように解決されます。 boost::base_from_member. 。また、すべての基本クラスのすべてのコンストラクター初期化子が完了する前に非静的メンバー関数を呼び出すことは未定義の動作であることに注意してください。

ただし、静的関数の呼び出しはまったく問題ありません。

class Derived: Base
{
public:
  int foo;
  static string bar(int f)
  {
    return stringof(f); // actually, something more complex
  };

  Derived(int f) : Base(bar(f)), foo(f)
  {
  };
}

基底クラスのコンストラクタは、常に派生クラスの他のメンバーを初期化する前に呼び出されます。あなたのコンパイラは、間違った順序で初期化子を持つために、あなたに警告を与えるべきです。唯一の正解は、パラメータとしてbar()かかりf静的メソッドを作ることである。

コンストラクタは、オブジェクトを構築し、まあ、ためです。これは、それが返されるまで、そこにオブジェクトが存在しない、ということ、そのための呼び出しメンバ関数だけで確実に動作するつもりはないことを意味します。他のみんなが言うように、静的な関数または非メンバ関数を使用します。

私もこれをやりたいと思ってきたが、私は最終的にあきらめた。
任意の適切な関数の呼び出しは、ベース()のパラメータとして使用することができる。
別のオプションは、int型を取ると「文字列」自体への変換を行いベースにコンストラクタを追加し、代替することです。

ただ、初期化()関数に自分のコンストラクタのコードを移動し、コンストラクタからそれを呼び出します。これは、そのような静的/非静的オーバーライドまたは何よりもはるかに簡単です。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top