2016-05-27 3 views
2

派生オブジェクトが別のオブジェクト内のベクトルに格納されているかどうかを調べる必要がある状況があります。私は自分が望むものを正確に行う方法や、それが可能かどうかを判断する方法を見つけ出すことはできません。私は、私が含んでいる解決策を持っていますが、目標を達成するための直接的な方法があれば、より洗練されたものになります。C++比較対象の関数にオブジェクト型を渡すことは可能です

これは私が何をしたいか、本質的である:

class IFruit 
{ 
public: 
    virtual ~IFruit(){}; 
}; 
class Apple : public IFruit {}; 
class Banana : public IFruit {}; 
class Orange : public IFruit {}; 

class FruitBowl 
{ 
public: 
    bool HasFruit(datatype?? FruitType) 
    { 
     for (auto iter : m_Fruit) 
     { 
      if (typeof(iter) == typeof(FruitType)) 
      { 
       return (true); 
      } 
     } 
     return (false); 
    } 

    vector< IFruit* > m_Fruit; 
}; 

int main() 
{ 
    FruitBowl Snacks; 
    Snacks.m_Fruit.push_back(new Banana); 
    Snacks.m_Fruit.push_back(new Apple); 
    Snacks.m_Fruit.push_back(new Orange); 

    if (Snacks.HasFruit(Orange)) 
    { 
     cout << "There is an orange available"; 
    } 

    return (0); 
} 

これは、目標を達成し、回避策ですが、それは私が根絶してみたいコールバックを提供する追加のステップがあります。

#include <vector> 
#include <iostream> 
#include <functional> 
using namespace std; 

class IFruit 
{ 
public: 
    virtual ~IFruit(){}; 
}; 
class Apple : public IFruit {}; 
class Banana : public IFruit {}; 
class Orange : public IFruit {}; 

class FruitBowl 
{ 
public: 
    bool HasFruit(function< bool(IFruit*) > fnCompareFruitType) 
    { 
     for (auto iter : m_Fruit) 
     { 
      if (fnCompareFruitType(iter)) 
      { 
       return (true); 
      } 
     } 
     return (false); 
    } 

    vector< IFruit* > m_Fruit; 
}; 

int main() 
{ 
    FruitBowl Snacks; 
    Snacks.m_Fruit.push_back(new Banana); 
    Snacks.m_Fruit.push_back(new Apple); 
    Snacks.m_Fruit.push_back(new Orange); 

    if (Snacks.HasFruit([](IFruit* TestFruit){ return (dynamic_cast< Orange* >(TestFruit) != nullptr); })) 
    { 
     cout << "There is an orange available"; 
    } 

    return (0); 
} 
+0

HasFruit()関数をテンプレート化することはどうですか?私はC++の専門家ではないので、まだ正確には取り組んでいませんが、テンプレートのようなものですが、テンプレート bool HasFruit(T *)const {...} ' –

+0

@DaveMのようなものです。私も同じでしたが、私の答えを見てください。 –

答えて

7

あなたはランタイム関数のパラメータとして型を渡すことはできませんが、コンパイル時テンプレート関数テンプレートのパラメータとして1を使用することができます。おそらく、

#include <vector> 
#include <iostream> 
#include <algorithm> 

class IFruit 
{ 
public: 
    virtual ~IFruit(){}; 
}; 
class Apple : public IFruit {}; 
class Banana : public IFruit {}; 
class Orange : public IFruit {}; 

class FruitBowl 
{ 
public: 
    template <typename T> 
    bool HasFruit() 
    { 
     return std::any_of(m_Fruit.begin(), m_Fruit.end(), 
          [](IFruit* fruit) { 
           return dynamic_cast<T*>(fruit) != nullptr; 
          }); 
    } 

    std::vector< IFruit* > m_Fruit; 
}; 


int main() 
{ 
    FruitBowl Snacks; 
    Snacks.m_Fruit.push_back(new Banana); 
    Snacks.m_Fruit.push_back(new Apple); 
    Snacks.m_Fruit.push_back(new Orange); 

    if (Snacks.HasFruit<Orange>()) 
    { 
     std::cout << "There is an orange available"; 
    } 
} 
+1

これは非常にエレガントな解決策です。ロジック –

+0

@MilesBudnek - タイプを渡す際の説明をありがとう。私はそれができるとは思っていませんでした、それを行う方法を見つけることができなかった、と間違いなく直接不可能であることを明らかに何かを明らかにすることができませんでした。答えがない理由に関する情報を見つけるのは難しいです。 – jgibbs

+0

'HasFruit'は' const'でもかまいません。 – Jarod42

2

私にとっては、すべての「フルーツタイプ」の列挙を作成し、それをパラメータのデータ型として使用することです。あなたは比較することができます

+0

私は、発信者が知る必要のない果物の種類について知ることから完全に離婚する必要があります。それは、言語が最終目標を達成するための機能を持っている場合は、主にコードクリーナーの作業バージョンを作成することです。 – jgibbs

+0

ああ、そうですよ!まあ、私はそれについて考えている/より良い答えを待っている。今のところ、私の限られた知識である限り、私はenum_より良い解決策を見いだすことはできません。私はうまくいけば多くがあると確信しています! –

+0

型は既に多態性によって定義されているので、enumを使用することは可能ですが、コードを著しく汚染し、不要な保守を作成します。私の現在の解決策はラムダを提供する1つの余分なステップしか持っていませんが、enumリストを追加し、それを派生クラスのすべてに設定すると不要な荷物が追加されます。 – jgibbs

2

何かこれは何ですか?

#include <iostream> 
#include <vector> 
using namespace std; 

class IFruit { 
    public: 
    virtual  ~IFruit(void) { } 
} ; 

class Apple : public IFruit { }; 
class Banana : public IFruit { }; 
class Orange : public IFruit { }; 

class FruitBowl : public vector<IFruit *> { 
    public: 
    template <typename T> bool HasFruit(void) const { 
     for (auto i : vector<IFruit *>(*this)) { 
      if (typeid(*i) == typeid(T)) return true; 
     } 
     return false; 
    } 
} ; 

int 
main(int, char **) 
{ 
    FruitBowl b; 

    b.push_back(new Apple); 
    b.push_back(new Banana); 
// b.push_back(new Orange); 

    if (b.HasFruit<Orange>()) // thanks M.M.! 
     cout << "found one" << endl; 
    else 
     cout << "no oranges" << endl; 

    return 0; 
} 

多分、電話をするのにもっとセクシーな方法がありますか? (Orange *)0はちょっと醜いです。

+1

パラメータを取り除き、関数を 'b.HasFruit ()'と呼びます –

+0

私はこれが好きです。これは私の道を歩み始めたが、HasFruit関数に型を渡す方法を考えることができなかったというパラダイムです。私は最終的には好きではないけれど、それは間違いなく大きなステップです。 – jgibbs

+0

'(オレンジ*)0'はデーヴをより多く持っています:) –

1

#include<vector> 
#include<iostream> 
#include<typeinfo> 
#include<memory> 

using namespace std; 

class IFruit 
{ 
public: 
    virtual ~IFruit(){}; 
}; 
class Apple : public IFruit {}; 
class Banana : public IFruit {}; 
class Orange : public IFruit {}; 

class FruitBowl 
{ 
public: 
    //uses tempalte to accept any type 
    template<typename FruitType> 
    bool HasFruit(FruitType fruit) 
    { 
     for (auto iter : m_Fruit) 
     { 
      if (typeid(* iter).hash_code() == typeid(fruit).hash_code()) 
      { 
       return (true); 
      } 
     } 
     return (false); 
    } 

    std::vector<IFruit*> m_Fruit; 
}; 

int main() 
{ 
    FruitBowl Snacks; 
    Snacks.m_Fruit.push_back(new Banana); 
    Snacks.m_Fruit.push_back(new Apple); 
    Snacks.m_Fruit.push_back(new Orange); 

    if (Snacks.HasFruit(Orange())) 
    { 
     cout << "There is an orange available"; 
    } 
    else{ 
     cout<<"No fruit available"; 
    } 

    return (0); 
} 

ライブデモ:http://coliru.stacked-crooked.com/a/37a3e1b4f5567775

+0

typeinfoでは '=='を直接使うことができ、ハッシュコードを作る必要はありません。 –

+0

オレンジのインスタンス化を必要としないので、私はDave.Mからの提案を好む – jgibbs

+1

私も同様に考えましたが、http://en.cppreference.com/w/cpp/language/typeidで簡単に見て、 assert(&ti1 == &ti2); //保証されていませんが、 'assert(ti1.hash_code()== ti2.hash_code()); //保証されています –

関連する問題