0

次のデータ構造があるとします。

struct Base
{
    Base(const int id, const std::string &name, const std::string &category):
        id(id), name(name), category(category) {}

    int         id;
    std::string name;
    std::string category;
};

struct A : public Base
{
    A(const int id, const std::string &name, const std::string &category,
      const int x, const int y) :
     Base(id, name, category), x(x), y(y) {}
    int x, y;
};

ID、名前、およびカテゴリが関数で認識されている派生クラスのベクトルを返す単一のファクトリ メソッドを作成したいと考えています。私が遭遇する問題はスライスです...

std::vector< Base* > getVector(...)

構造体 A のデータ メンバーが失われました。(dynamic_cast を A に戻して、製品コードで受け入れられるようにしますか?)

だから私はこのテンプレートメソッドを持っていますが、それでも最善の解決策だとは思いません:

template< class T >
std::vector< T > getVector()
{
    std::vector< T > retVal;

    retVal.push_back(T(45, "The Matrix", "Science Fiction"));
    retVal.push_back(T(45, "Good Luck Chuck", "Comedy"));
    ...
    return retVal;
}

テンプレート法以外に良い解決策はありますか?

4

2 に答える 2

1

私は実際にあなたのテンプレートがおそらく最良の解決策だと思います、少なくともそれは慣用的なC++です。

などのRTTIを使用するdynamic_castこともできますが、安全性がかなり低く(実行時とコンパイル時の型チェック)、多くの場合効率が低下します。ただし、場合によっては(または実際には非常に頻繁に) 、実行時にのみポリモーフィズムを決定する必要があります(たとえば、同じ中に異なる派生オブジェクトが必要でstd::vector、固定長を使用できない場合std::tuple)。次に、すでに準備したように、オブジェクトではなく基本クラスのポインタのベクトルを使用して、スライスの問題を回避できます。(プレーンな)ポインタの問題は、C ++の自動メモリ管理をいくらか回避することです。std::vector<Base*>スコープ外になると、ポイントされた派生オブジェクトはそうではありません。アクセスできない場所にぶら下がっていることで削除されました。メモリリークが発生しています。そのため、この継承の使用方法に大きく依存するJavaのような言語は、ガベージコレクションされます。この問題は他の場所で説明されています。推奨される解決策は、に置き換えることBase*ですstd::unique_ptr<Base>

これを実行すると、ランタイムポリモーフィック関数を利用できるようになります。通常必要ありませんがdynamic_cast、異なる派生インスタンスが仮想メンバー関数として異なるすべてを記述します。

于 2013-02-18T22:58:40.780 に答える
1

あなたが望んでいるので、あなたが求めていることは疑わしいようです:

  • 実行時までオブジェクトの作成を抽象化するには
  • コンパイル時のオブジェクト作成後に特定のメンバーにアクセスするには

したがって、まともに機能させる方法はありません。テンプレート コードは、呼び出し元のサイトでオブジェクトの型を静的に認識する必要があるため、オブジェクトの作成は抽象化されません。

私のアドバイスは、あなたの問題についてもう一度考えてみることです: なぜ動的なファクトリが必要なのですか? すべてのオブジェクトがBaseクラス内のアクセサを共有できないのはなぜですか?

これら 2 つの質問に明確に答えられない場合は、そもそもこのクラス階層を持つべきではないことを意味している可能性があります。

于 2013-02-18T22:50:09.343 に答える