5

Apple.h

class Apple {
public:
    Apple(int);
    static int typeID;
private:
    int id_;
};

Apple.cpp

#include "Apple.h"
Apple::Apple(int pID) {
    id_ = pID;
}

Apple と同一の Potato.h、Potato.cpp

Storage.h

#pragma once
#include "Apple.h"
#include "Potato.h"
#include <vector>
class Storage {
public:
    Storage();
    template<typename foodName> void store(foodName * object){
        (*getBasket<foodName>()).push_back(object);
    };
    template<typename foodName> int countSize(){
        return (*getBasket<foodName>()).size();
    };

private:
    std::vector<Apple*> applebasket_;
    std::vector<Potato*> potatobasket_;
    template <typename foodName> std::vector<foodName*> * getBasket(){
        std::vector<foodName*> * result;
        switch(foodName::typeID){
            case 0:
                result = &applebasket_;
                break;
            case 1:
                //result = &potatobasket_;
                break;
        }
        return result;
    } 
};

ストレージ.cpp

#include "Storage.h"
int Apple::typeID;
int Potato::typeID;
Storage::Storage() {
    Apple::typeID = 0;
    Potato::typeID =1;
}

main.cpp

#include "Storage.h"
#include <iostream>
int main() {
    Apple* apple;
    Potato* potato;
    Storage storage;
    int i;
    for(i = 0;i < 7;i++){
        apple = new Apple(i);
        storage.store<Apple>(apple);  
    }      
    std::cout<<storage.countSize<Apple>();
    return 0;
}

このコードは機能し、正しいサイズのベクトルを出力しますが、switch ステートメント (Storage.h 内) の case 行がコメント解除されている場合、コンパイラ (g++) は「エラー: 'std::vector < Potato*>* ' を 'std に変換できません」をスローします。 ::vector< Apple*>* ' in assignment". とにかく両方のケースを試しているコンパイラのようなもので、それが可能かどうか、またこれを回避する方法がわかりません。私はこれについて助けが必要で、おそらく全体についてのアドバイスが必要です(さまざまなタイプのコンテナ用の1つのインターフェース)。最近C ++の学習を開始しましたが、おそらくここでこれを行う方法は完全に混乱しています。

4

4 に答える 4

2

caseタイプが両方で異なるため、両方がコンパイルする必要があるため、コードはコンパイルされませんcase

この問題の解決策の 1 つは、関数 template as の代わりにオーバーロードを使用することです (つまり、クラスには必要ありませtypeIDん!)。

std::vector<Apple*> * get_basket(Apple *)
{
   return &applebasket_;  //return pointer to the apple basket
}

std::vector<Potato*> * get_basket(Potato *)
{
   return &potatobasket_; //return pointer to the potate basket
}

そしてそれを次のように呼び出します:

template<typename FoodType> 
void store(FoodType * object)
{
    std::vector<FoodType> * basket = get_basket(static_cast<FoodType*>(0));
    basket->push_back(object);
}

ここでの秘訣は、2 つのオーバーロードがあり、それぞれが異なる型の引数を 1 つ取るため、 を使用して、型または型のいずれかになる式のstatic_cast<FoodType*>(0)に基づいてコンパイラが正しいオーバーロードを選択できるようにすることです。static_cast<FoodType*>(0)Apple*Potato*


@Gorpikはコメントで、両方 (これと他のソリューション) が醜いので、この問題を解決するための別の試みを示しました。

base_storageクラス テンプレートを次のように定義します。

template<typename FoodType>
class base_storage
{
    std::vector<FoodType*> m_storage;
    public:
        void store(FoodType *foodItem)
        {
            m_storage.push_back(foodItem);
        }
        size_t count() const
        {
            return m_storage.size();
        }
};

この基本クラスは1種類の食品のみを格納しますが、問題では2種類の食品を格納する必要があります。Storageそのために、上記のクラス テンプレートから派生する別のクラスを次のように定義します。

class storage : private base_storage<Apple>, private base_storage<Potato>
{
    public:
        template<typename FoodType> 
        void store(FoodType * foodItem)
        {
            base_storage<FoodType>::store(foodItem);
        }
        template<typename FoodType> 
        size_t count() const
        {
            return base_storage<FoodType>::count();
        }
};

ここで 2 つの点に注意してください。

  • 現在、クラスstorageにはメンバー データがありません。テンプレート引数のタイプに基づいて選択された基本クラスへの呼び出しを転送するだけですFoodType
  • これは、基本クラスからプライベートに派生します。だから、それはis-a関係ではありません。

このソリューションのオンライン デモを参照してください: http://ideone.com/Ykjo5

このソリューションの優れた点は、 3種類の食品で機能させたい場合、次のように3 つの基本クラスから派生させるだけでよいことです。

class storage : private base_storage<Apple>, 
                private base_storage<Potato>,
                private base_storage<Mango>   //added line!
{

     //same as before; no change at all !

};

デモ: http://ideone.com/lnMds

于 2012-06-14T14:13:51.180 に答える
2

typeID フィールドを使用する必要さえありません。コンパイラにすべての仕事をさせます。

class Storage {
public:
    Storage();
    template<typename foodName> void store(foodName * object){
        (*getBasket<foodName>()).push_back(object);
    };
    template<typename foodName> int countSize(){
        return (*getBasket<foodName>()).size();
    };

private:
    std::vector<Apple*> applebasket_;
    std::vector<Potato*> potatobasket_;

    template <typename foodName> std::vector<foodName*> * getBasket();
};


template <> std::vector<Apple*> * Storage::getBasket()
{
    return &applebasket_;
} 
template <> std::vector<Potato*> * Storage::getBasket()
{
    return &potatobasket_;
} 
于 2012-06-14T14:20:23.377 に答える
2

std::vector<Apple *>std::vector<Potato *>、異なるタイプです。C++ テンプレートは、コンパイル時にクラス定義とそのすべてのコードの完全なコピーを生成するため、結果の具体的な型の間にはまったく関係がありません。

ApplePotatoが共通の親クラスを共有している場合、Food両方の種類のものを a に格納できるとしますがstd::vector<Food *>、それでもaが期待されていたstd::vector<Apple *>場所に aを返すことはできません。std::vector<Food *>

getBasket()メソッドは戻り値の型をテンプレート化することでこれを回避しようとしますが、テンプレートはコンパイル時に評価され、switch ステートメントは実行時に評価されるため、回避できませ。コンパイラはfoodStuff、プログラムが実行を開始する前にパラメータが何であるかを決定する必要があるため、switch ステートメントの結果がどうなるかはわかりません。とにかく決定を下す必要がありreturn、関数本体で見つかった最初のステートメントから導出できる結果はなくなり、2番目のステートメントが無効になるという不幸な結果になります。

Appleしたがって、 とを別々に保存および取得するかPotato(他の回答のいくつかが示唆しているようにテンプレートを使用する可能性があります)、または共通の親型を理解するものにそれらを保存できるように継承を使用する必要があります。

于 2012-06-14T14:33:22.013 に答える
0

getBasket2 つのケースに特化します。

または、このようにアブストレーション レベルを混在させず、ジャガイモとリンゴの容器を別々に用意することをお勧めします。

于 2012-06-14T14:17:26.023 に答える