Массив шаблонных объектов - PullRequest
4 голосов
/ 30 апреля 2011

Я не знаю, как решить проблему с шаблонами и наследованием.

В моем коде есть шаблонный класс, который выглядит примерно так:

template<typename T>
class Derived : public Base{
     T value;
public:
     Derived(T arg) { value=arg; };
     T getValue() { return value;};
};

class Base{
};

Единственная цель моего Базового класса - сгруппировать массив объектов класса Derived. Параметр T обычно является double, float или complex, хотя int и структуры могут также стать полезными. (Позже будет еще несколько похожих производных классов с несколькими дополнительными функциями.)

Я могу создать такую ​​группу

Base** M = new Base*[numElements];

и присваивать им элементы производного класса, например ::

M[54] = new Derived<double>(100.);

Но как я могу узнать, что 55-й элемент имеет значение 100 позже? Мне нужно что-то вроде

virtual T getValue() = 0;

но T - это имя типа производного класса и может отличаться для любых двух элементов этого массива.

Ответы [ 6 ]

4 голосов
/ 30 апреля 2011

Шаблон Visitor, вероятно, является вашей лучшей ставкой здесь.Код, повторяющий массив, должен предоставить объект «Посетитель», который знает, как обрабатывать каждый из различных типов.

struct NumericVisitor
{
    virtual void visit(double) = 0;
    virtual void visit(int) = 0;
    virtual void visit(unsigned char) = 0;
};

struct Visitable
{
    virtual void visitValue(NumericVisitor& visitor) = 0;
};

template<typename T>
class Derived : public Visitable
{
     T value;
public:
     Derived(const T& arg) value(arg) {}
     void visitValue(NumericVisitor& visitor) { visitor.visit(value); }
};

Теперь вы можете определять посетителей для каждой операции, которую вы хотите выполнить в коллекции, напримерпреобразовать каждый элемент в строку с различным форматом для каждого типа или сохранить каждый элемент в файл, где каждый тип может занимать различное количество места.

2 голосов
/ 01 мая 2011

Вы можете добавить перегруженные has_value() методы к классу Base:

class Base
{
public:
    virtual ~Base () {}
    virtual bool has_value (int i) {return false;}
    virtual bool has_value (double d) {return false;}
    virtual bool has_value (const std::string& s) {return false;}
    // etc.
};

один из которых вы переопределяете в классе Derived:

template<typename T>
class Derived : public Base
{
     T value;
public:
     Derived(T arg) {value=arg;}
     T getValue() { return value;}

     virtual bool has_value (T t)
     {
         return t == value;
     }
};

например:.

bool test ()
{
    std::vector<Base*> bases;
    bases.push_back (new Derived<double> (1.234));
    bases.push_back (new Derived<int> (100));
    bases.push_back (new Derived<std::string> ("zap"));

    for(std::vector<Base*>::const_iterator iter = bases.begin (); iter != bases.end (); ++iter)
        if ((*iter)->has_value (100))
            return true;
    return false;
}

Обратите внимание, вы не можете заменить методы has_value в базовом классе одним шаблонным методом, поскольку виртуальные методы не могут быть шаблонизированы.

0 голосов
/ 30 апреля 2011

используйте boost :: any для хранения объектов в массиве.Затем, когда вы захотите работать с ним, вы можете использовать boost :: any_cast для возможных типов, которые у вас есть.

0 голосов
/ 30 апреля 2011

NO.Практически невозможно иметь такую ​​функцию по двум причинам:

  1. Base не может быть шаблоном, так как вы хотите, чтобы универсальный дескриптор сохранял массив, который может содержать любой тип Derived like <int>, <double>, <float>, any struct <abc>.
  2. Вы не можете иметь метод template virtual внутри Base, потому что язык не позволяет это

Простой простой способ решения этой проблемы -иметь метод "getter" для каждого типа, такого как get_double(), get_int(), get_float(), get_abc() и так далее.Однако ваш Base будет загроможден такими методами.

0 голосов
/ 30 апреля 2011

Вы можете использовать dynamic_cast, чтобы узнать, что это за тип (в дополнение к тому, что говорит @StackedCrooked). Для этого потребуются некоторые виртуальные функции, определенные в базовом классе, но вам уже нужен виртуальный деструктор (чтобы иметь возможность удалять значения через указатели базового класса).

В качестве альтернативы вы можете попробовать повысить :: вариант или повысить :: любой:)

0 голосов
/ 30 апреля 2011

Добавьте метод "getDouble" в ваш базовый класс. Производные классы должны затем реализовать этот метод и привести их собственный тип к удвоению, если требуется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...