2016-05-27 12 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++, поэтому я еще не разработал его, но что-то вроде 'template bool HasFruit (T *) const {...}' –

+0

@DaveM. У меня было то же самое, хотя, см. Мой ответ. –

ответ

7

Вы не можете передать тип в качестве параметра функции во время выполнения, но вы можете использовать один в качестве параметра времени компиляции шаблона из шаблона функции:

#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

Это очень элегантное решение, +1 для простоты логика –

+0

@MilesBudnek - Спасибо за разъяснение при передаче типа. Я не думал, что это можно сделать, не смог найти способ сделать это, и определенно не мог раскрыть что-либо прямое, что это было невозможно. Трудно найти информацию о вещах, которые не имеют оснований для ответа. – jgibbs

+0

'HasFruit' может даже быть' const'. – Jarod42

2

Для меня решение было бы сделать перечисление для всех «типов фруктов» и использовать его в качестве типа данных вашего параметра. Вы можете сделать сравнение, а затем

+0

Мне нужно, чтобы звонящий был полностью оторван от знания о типах фруктов, о которых он не должен знать. Это в первую очередь о том, чтобы сделать рабочую версию кода более чистым, если язык имеет функции для достижения конечной цели. – jgibbs

+0

О, верно! Ну, я думаю об этом/ожидая лучшего ответа. Прямо сейчас, поскольку мои ограниченные знания касаются, я не нахожу лучшего решения, чем enum_. Я уверен, что будет много надежд! –

+0

Хотя использование перечислений было бы возможно, оно значительно загрязнило бы код и создало бы ненужное обслуживание, учитывая, что типы уже определены полиморфизмом. Мое текущее решение имеет только один дополнительный шаг обеспечения лямбда, тогда как добавление списка перечислений и установка его во всех производных классах просто добавят ненужный багаж. – 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

'(Orange *) 0' имеет больше swag Dave :) –

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()); // protected' –