2015-11-03 2 views
0

Я должен хранить разные типы данных в одном массиве для моего проекта. Я создал класс шаблона для генерации объектов.Объекты класса шаблонов для хранения объектов в массиве

template<class Queue> 
class Template { 

public: 
    Queue value; 
    Template(Queue input) { 
     value = input; 
    } 

}; 

Но я не могу держать их в одном массиве без использования абстрактного класса. Для этого я создал массив указателей void. И я использовал его понравилось;

void *array[21]; 
array[index] = new Template<int>(number); 
array[index] = new Template<string>(text); 

Есть ли возможное решение без абстрактных классов? Я имею в виду, могу ли я удерживать эти объекты шаблона в массиве класса шаблона?

+1

You непонятных параметров шаблона возможно. Как 'int' представляет« очередь »на самом деле? –

+0

Нет, я буду использовать разные типы данных с реализацией очереди. Из-за этого я назвал это. – jesta

+0

Вам понадобится промежуточный шаблонный класс, например 'template class Queue;' вероятно, где 'T' создается как' int', 'std :: string' соответственно. –

ответ

5

Создать иерархию и воспользоваться динамическое связывание:

class Base { 
public: 
    virtual ~Base() {}; 
    // ... 
}; 

template<class Queue> 
class Template : public Base { 
    Queue value; 
public: 
    Template(Queue const &input) :value(input) {} 
    // ... 
}; 

И использовать его как:

Base *array[21]; 
array[index] = new Template<int>(number); 
array[index + 1] = new Template<string>(text); 

Кроме того, вместо того, чтобы использовать необработанный массив и сырые указатели использовать STL объекты, как std::array смарт-указатели (например, std::shared_ptr<Base> или std::unique_ptr<Base>):

std::array<std::unique_ptr<Base>, 21> arr; 
arr[index].reset(new Template<int>(number)); 
arr[index + 1].reset(new Template<string>(text)); 

Также предпочитает инициализировать переменные-члены в списке инициализаторов конструктора, чем в его теле.

+0

Хороший ответ. также обратите внимание, что если он нуждается в значении, он может иметь виртуальную функцию в Base <> и переопределить ее в Шаблоне, воспользовавшись вариантами возврата ко-вариантами! –

+0

@ Moo-Juice Ковариантные типы возврата велики, но не будут работать для его примера 'int' и' std :: string'. Базовый класс здесь позволяет хранить эти значения в однородном массиве, но мне все еще нужно задаться вопросом, зачем ему это нужно. Как и в случае с ним, ему придется «dynamic_cast» каждый раз, когда он хочет вернуть данные. – SirGuy

+0

@NathanOliver, на самом деле это неправда. Вы можете переопределить виртуальную функцию и предоставить другой тип возврата при условии, что он является ко-вариантом. Однако, как указывает GuyGreer, в этом случае он не подходит. –

2

Это обычно признак того, что вы должны пересмотреть свою структуру кода на более высоком уровне, чтобы вам вообще этого не нужно.

В противном случае у вас есть четыре варианта, которые я вижу (пять, если считать «не делай этого» выше):

  1. Используйте однородный тип, который может хранить все типы данных (например, a std::string и проанализировать числовую информацию при необходимости). Эта функциональность может быть обернута в класс, который предоставляет функции-члены, чтобы сделать это проще.

  2. Используйте boost::variant, если вы новичок в C++, тогда я не рекомендую сразу заниматься этим.

  3. Используйте базовый класс, как объяснено 101010. Я хотел бы добавить, что вы можете перечисление в базовом классе, который говорит вам, какой тип данных хранится

  4. Использовать boost::any, это еще сложнее чтобы использовать, чем вариант, хотя его легче понять.

Без дополнительной информации о том, чего вы пытаетесь достичь, мы не можем дать никаких рекомендаций относительно того, как действовать дальше.

+0

@jesta, что будут делать эти команды иначе, чем «положить» вещи? Где они их кладут? Сколько вам нужно знать о том, какие типы вы помещаете где-то? – SirGuy

+0

@jesta, из того, что вы говорите, я бы рекомендовал решение 1. – SirGuy

1

Я бы сделал это с использованием вариантов.Вы можете раскрутить свой own но предпочитают использовать boost::variant:

#include <boost/variant.hpp> 
#include <iostream> 
#include <string> 

using namespace std; 

template<class Queue> 
class Template 
{ 
public: 
    Queue value; 
    Template() = default; 
    Template(Queue input) { 
     value = input; 
    } 
}; 

template<typename T> 
std::ostream& operator<<(std::ostream& os, Template<T> const& t) 
{ 
    os << t.value; 
    return os; 
} 

int main() 
{ 
    using v_t = boost::variant<Template<int>, Template<string>>; 

    v_t ar[2]; 

    ar[0] = Template<int>(1); 
    ar[1] = Template<string>("lmfao"); 

    for (auto&& elem : ar) cout << elem << endl; 
} 

Demo

Обратите внимание, что

  • v_t тип варианта
  • v_t может иметь несколько типов, среди которых вы можете заполнить массив
  • оператор вывода был перегружен только для демонстрации
  • вы получите дополнительную функциональность по boost::visitor
Смежные вопросы