2013-07-11 4 views
0

После не работает:Как сделать вектор абстрактного класса шаблона

std::vector<IRule*> vec; 
RuleRangeDouble *rule = new RuleRangeDouble(0, 100); 
vec.push_back(rule); 

Теперь как можно сделать вектор различных правил? Я знаю, я должен использовать указатели ... Но что еще мне нужно сделать, чтобы заставить это работать? Как я могу изменить свою базовую структуру, чтобы получить эту работу?

Я использую интерфейс как следующие:

// Interface 
    template <typename T> 
    class IRule 
    { 
     public: 
      virtual bool isValid(T value) = 0; 
    }; 

И мой пример класса выглядит следующим образом:

class RuleRangeDouble : public IRule<double> 
    { 
     private: 
      double min; 
      double max; 
     public: 

      bool isValid(double value) 
      { 
.... 
      }; 
    }; 
+0

Почему это не работает? Если 'RuleRangeDouble' происходит публично из« IRule », нет причин, по которым он не должен работать. –

+0

@JamesKanze Это не так, как 'IRule' является шаблоном класса. – juanchopanza

+0

@juanchopanza Я пропустил это. Если 'IRule' является шаблоном,' IRule * 'не является допустимым типом. –

ответ

1

Вы можете осуществить что-то вроде getBestValidValue() несколько способов. Одним из них является определение специального общее (но не шаблон) тип возвращаемого значения, которые будут использоваться для getBestValidValue(), а также в качестве аргумента типа для isValid(value) (ответ juanchopanza был неисправен здесь):

class ValueType 
{ 
    enum { is_int, is_double } my_type; // add more if you want 
    union { my_int; my_double; };  // union only works for simple types 
public: 
    // implicit construction from allowed types 
    ValueType(int x) : my_type(is_int), my_int(x) {} 
    ValueType(double x) : my_type(is_double), my_double(x) {} 
    // use SFINAE for is<type>() function 
    template<typename T> 
    typename std::enable_if<std::is_same<T,int>::value,bool>::type 
    is() const { return my_type==is_int; } 
    template<typename T> 
    typename std::enable_if<std::is_same<T,double>::value,bool>::type 
    is() const { return my_type==is_double; } 
    // implicit type conversion to allowed types 
    // note: does not assert(is<T>()) 
    operator int() { return my_int; } 
    operator double() { return my_double; } 
}; 

class IRule 
{ 
public: 
    virtual bool isValid(ValueType const&) const = 0; // fixed bug in juanchopanza's answer 
    virtual ValueType getBestValidValue() const = 0; // return any type of value 
    virtual ~IRule() {} 
}; 

template<typename T> 
class Rule : public IRule 
{ 
protected: 
    virtual bool valid(T) const = 0; 
    virtual T bestValidValue() const = 0; 
public: 
    bool isValid(ValueType const&value) const 
    { 
    return value.is<T>() 
     && valid(value);   // implicit type conversion to T 
    } 
    ValueType getBestValidValue() const 
    { 
    return bestValidValue();  // implicit construction of ValueType 
    } 
    .... 
} 
+0

Большое спасибо, я получил это решение для работы, и он делает то, что я хочу. Я не могу использовать 'std :: enable_if', потому что я должен использовать Visual Studio 2005, и библиотека не является частью этого ... – prom85

+0

@ prom85 вы можете легко определить свой 'enable_if':' template struct enable_if {typedef T type; }; 'и' template struct enable_if {}; ' – Walter

+0

спасибо. На самом деле, у меня нет доступа к полной библиотеке ''. – prom85

3

вектор должен быть вектором действительного типа, например std::vector<IRule<double>*>. Irule сам по себе не является типом, это шаблон класса. Таким образом, вам понадобится

std::vector<IRule<double>*> vec; 
RuleRangeDouble *rule = new RuleRangeDouble(0, 100); 
vec.push_back(rule); 

Если параметр шаблона не является частью интерфейса, вы можете ввести общий базовый класс. Не забудьте дать ему virtual деструктора:

class IRule 
{ 
    public: 
     virtual bool isValid(T value) = 0; 
     virtual ~IRule() {} 
}; 

template <typename T> 
class Rule : public IRule 
{ 
    ..... 
}; 

class RuleRangeDouble : public Rule<double> 
{ 
    .... 
}; 

Тогда ваш оригинальный случай использования образец будет работать:

std::vector<IRule*> vec; // IRule really is a type now 
RuleRangeDouble *rule = new RuleRangeDouble(0, 100); 
vec.push_back(rule); 
+0

Это моя проблема, я хочу вектор неопределенного типа, просто указатель ... Я хочу вызвать isValid для всех объектов в моем векторе ... Независимо от того, какой тип они ... Потому что есть больше классов, чем просто Класс RuleRangeDouble .. Я не знаю, может быть, для этого существует какое-то решение оболочки? Я просто не могу думать об одном ... и я не мог заставить кого-нибудь, кого я нашел, работать ... – prom85

+0

@ prom85 тогда вам нужен общий базовый класс или вариант типа, например 'boost :: any' или' повышение :: variant'. – juanchopanza

+0

На самом деле, я не знаю, как вы это понимаете, базовый класс должен быть выше интерфейса IRule и, следовательно, должен быть также шаблоном ... и я не могу использовать boost, к сожалению ... – prom85

Смежные вопросы