0

継承と STL リスト ライブラリの使用に問題があります...

たとえば、2 つの派生クラス (すべての比較演算子が定義されている) を持つ抽象基本クラスがあるとします。リストは次のように宣言されます

list<StoreItem*> items;

Food または Clothing という名前の (抽象基本クラス StoreItem の) 派生クラスを挿入しています。挿入しようとしている新しい StoreItem ポインターを作成します。

StoreItem* item = new Food(arguments here);

今、私はこの新しいアイテムを(順番に)リストに挿入したいと思っています。私の試みは次のとおりです:

list<StoreItem*>::iterator iter;
for (iter = inventory.begin(); iter != inventory.end(); iter++)
{
    if (*item < **iter)
        break; // break out to insert
}

inventory.insert(iter, item);

私が間違っていることはありますか?また、インベントリから情報を取得するにはどうすればよいですか? (例: コピー コンストラクターを使用した Food tempFruit(**iter))。

前もって感謝します!良い一日を過ごしてください。

4

5 に答える 5

1

を定義していれば、これは機能しますStoreItem::operator<が、もう少し良い別の方法があります。STL は寒さで分類されています。<for を定義してStoreItem*から、 を使用できますlist<...>::sort()

SortedItemList(そして、内部で並べ替えを処理する独自のクラスを定義することを既に考えているでしょう。)

はい、tempMovie(**iter)他の方法の中でも機能します。

編集:

在庫から何かを引き出すことについて、私はあまりにも早すぎたと思います。これは機能します:

list<StoreItem *>::iterator citr = items.begin();

Food *fp = dynamic_cast<Food *>(*citr);

Food ff(*fp);

これStoreItem*が実際には a を指していることを知っておく必要があることに注意してください。これがFooda を指しているClothing場合、セグメンテーション違反またはそれ以上のエラーが発生します。調べるには、独自の を実装するStoreItem::whatTypeAmI()か、C++ のランタイム型識別を使用します。

#include <typeinfo>
...
Food a;
StoreItem *sp = *citr;
if(typeid(*sp)==typeid(a))
{
  // it's a Food
}

StoreItem*(型を知らなくても、 を使って多くのことを実行できることに注意してStoreItem&ください。ポリモーフィズムはあなたの友達です。)

于 2011-10-19T04:25:50.213 に答える
1

リストから取得する項目はFoodインスタンスであると想定しています。ただし、コンパイラはそれを知りません。Foodリスト内の項目 (明らかな type の項目) からの新しいインスタンスを作成する場合、または互換性のあるものStoreItemを呼び出そうとしています。Food::Food(const StoreItem)なんで?イテレータは、オブジェクトのインスタンス、またはなどの から派生した任意のクラスのインスタンスである可能性StoreItem*があるを指しているためです。StoreItemStoreItemFood

他の投稿者がコメントしているように、ポリモーフィズムは成功へ鍵です。アイテムが であることを本当に知る必要がありFoodますか? そうでない場合は、すべてのストア アイテム (価格、シリアル番号など) で共有されるインターフェイスにアクセスします。アイテムについて特定のことを知る必要がある場合は、そのタイプを推測することができます:

Food *food = dynamic_cast<Food*>(*iter);
if (food != NULL) {
   // perform food related logic
   std::cout << "Ingredients: " << food->ingredients() << std::endl;
}
else {
   std::cout << "I can't eat that!" << std::endl;
}
于 2011-10-19T17:46:15.100 に答える
0

あなたが頼ることができる解決策を自作する代わりにboost::ptr_list. ポインターを STL のようなコンテナーに格納する場合は、作業がずっと楽になります。operator<次に、挿入しようとしているアイテムを定義するだけです。ptr_list共有所有権で使用することを意図していないことに注意してください。これを実現するには、タイプに特化して使用std::shared_ptrSします。std::liststd::lessshared_ptr

于 2011-10-19T13:34:03.933 に答える
0

基本クラスへの 2 つのポインター間の比較演算子を定義できれば、他のコードを記述しなくても、順序付けられたコレクションを取得できます。アプリケーションによっては、セットまたはヒープ、さらにはマップが必要になる場合があります。これを行うイディオムは次のとおりです...(ベースは文字列から公的に派生しています)。

template<>
struct std::less<base*>
{
   bool operator()(const base* lhs, const base* rhs) const
   {
      return *lhs < *rhs;
   }
};

typedef set<base*> S;

int _tmain(int argc, _TCHAR* argv[])
{
    base able(std::string("able"));
    base baker(std::string("baker"));
    base charlie(std::string("charlie"));

    S inventory;
    inventory.insert(&charlie);
    inventory.insert(&able);
    inventory.insert(&baker);

    for (S::iterator i = inventory.begin(); i != inventory.end(); ++i)
        std::cout << **i << endl;
    return 0;
}

出力:
エイブル
ベイカー
チャーリー

このイディオムを発見する前に、しばらくブラブラすることは可能です。何が起こっているかというと、ライブラリ テンプレート std::less を T=base*; に特化しているということです。これは、魔法のように std::set (または他の順序付けられたコンテナー) のデフォルトのコンパレーター引数に挿入されます。

于 2011-10-19T04:23:13.477 に答える
0

へのポインターに対して定義された比較関数を使用すると、次のStoreItemように挿入コードを短縮できます。

bool less_ptr( const StoreItem*& lhs, const StoreItem*& rhs )
{
    return *lhs < *rhs;
}

挿入:

StoreItem* item = new Food(arguments here);
inventory.insert( std::upper_bound( inventory.begin(), inventory.end(), item, less_ptr ), item);

std::upper_bound( #include <algorithm>) は、リストがソートされていることを前提としているため、リストを常にソートしている場合に適用されます。

データの引き出しに関しては、次の 2 つの点を考慮する必要があります。

  1. コピー コンストラクターを使用してオブジェクトを再作成すると、新しいオブジェクトが作成され、それらを変更してもリスト内のオブジェクトは変更されないため、ポインターを使用することをお勧めします。
  2. 格納されているオブジェクトのタイプに応じて、コード パスを分割する必要があります。

あなたはこれを行うことができます:

Food* foodObj = NULL;
Clothing* clothesObj = NULL;

list<StoreItem *>::iterator it = inventory.find( /* something */ );
StoreItem* item = *it;

item->DoSomethingWithAnyStoreItem(); // It's best to only use such methods

// But if you need something only a derived class has...
foodObj = dynamic_cast<Food*>(item);
clothesObj = dynamic_cast<Clothes*>(item);

if( foodObj != NULL )
{
    foodObj->DoSomethingWithFood();
    Food newFood( *foodObj );
    newFood.DoSomethingWithCopyOfFood();
}
else if( clothesObj != NULL )
{
    clothesObj->DoSomethingWithClothes();
}
else
{
    // It's neither Food, nor Clothes
}
于 2011-10-19T14:14:33.037 に答える