2

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

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)
  {
  };
}
4

6 に答える 6

4

はい、 fooをパラメーターとして取り、文字列を返す関数 (静的クラス メソッドまたは通常の関数) を使用することは、適切な解決策です。コードの重複を防ぐために、Derived::bar から同じ関数を呼び出すことができます。したがって、コンストラクタは次のようになります。

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

Base コンストラクターの呼び出しをリストの最初に配置して、初期化が発生する順序を強調します。すべてのクラス メンバーは、クラス本体で宣言されている順序で初期化されるため、初期化子リストの順序は影響しません。

これは、問題に対する非常にクリーンで機能的なアプローチです。ただし、代替案を検討したい場合は、Derived クラスと Base クラスの間の関係を継承する代わりに構成を使用することを検討してください。

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();
    }
};

特定の状況の長所と短所を考慮する必要があります。Base への参照を保持する Derived を使用すると、初期化順序をより詳細に制御できます。

于 2008-12-17T16:38:57.707 に答える
4

初期化子リストでは、静的関数のみを呼び出すことができます。あなたのコードでそれを持っている方法:

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)
  {
  };
}
于 2008-12-17T16:42:54.000 に答える
2

基本クラスのコンストラクターは、派生クラスの他のメンバーを初期化する前に常に呼び出されます。コンパイラは、初期化子の順序が間違っていることを警告するはずです。唯一の正しい解決策は、パラメーターとしてbar()受け取る静的メソッドを作成することです。f

于 2008-12-17T16:44:46.710 に答える
1

コンストラクターは、オブジェクトを構築するためのものです。これは、返されるまでそこにオブジェクトがないことを意味し、したがって、メンバー関数の呼び出しが確実に機能しないことを意味します。他の人が言うように、静的関数または非メンバー関数を使用してください。

于 2008-12-17T16:54:19.763 に答える
0

私もやってみたいと思っていましたが、結局諦めました。
Base() のパラメータとして、任意の適切な関数呼び出しを使用できます。
もう 1 つのオプションは、int を取り、「文字列」自体への変換を行う Base に代替コンストラクターを追加することです。

于 2008-12-17T16:41:34.237 に答える