Преобразование из вектора STL подкласса в вектор базового класса - PullRequest
7 голосов
/ 18 апреля 2011

Мне интересно, возможно ли преобразовать вектор значений производного класса в вектор значений базового класса. В частности, я хочу иметь возможность передавать вектор объектов базового класса в функцию, формальные параметры которой принимают вектор базового класса. Это не представляется возможным напрямую, так как в следующем примере кода выдается ошибка (с использованием g ++):

#include <vector>

class A {
};

class B : public A {
};


void function(std::vector<A> objs) {
}

int main(int argc, char **argv) {
    std::vector<B> objs_b;
    objs_b.push_back(B());
    function(objs_b);
}

test.cc: 16: ошибка: преобразование из 'std :: vector >' в нескалярный тип 'std :: vector > 'запрошено

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

Ответы [ 2 ]

11 голосов
/ 18 апреля 2011

Нет, это не так. vector<B> не является производным от vector<A>, независимо от того, что B является производным от A. Вам придется как-то изменить свою функцию.

Более идиоматически подход C ++ может заключаться в том, чтобы шаблонировать его и использовать для него пару итераторов - вот почему различные стандартные библиотечные функции (<algorithm> и т. Д.) Работают таким образом, поскольку отделяют реализацию алгоритма от на что он работает.

3 голосов
/ 18 апреля 2011

Иногда есть способы обойти это.Получите удовольствие от Boost и некоторых шаблонных пакетов метапрограммирования, которые они имеют или используют.В частности, я бы посмотрел на is_base_of для подобных целей в сочетании с частичной специализацией шаблонов.

Например, если вы хотите сделать какую-то магическую хитрость шаблона:

template<typename T, bool Allowed>
struct TemplateVectorCode;

Вы делаете предварительное объявление шаблонного класса.Затем вы создаете специализацию с «истинным» логическим значением:

template<typename T> struct TemplateVectorCode<T, true>{
    void operator(const std::vector<T>& myVector) const{ //definition in here }
};

Наконец, вы используете это с is_base_of, чтобы только создавать экземпляры вашего функтора шаблона следующим образом:

template<typename T, typename Base>
struct MyFunction : TemplateVectorCode<T, boost::is_base_of<Base,T>::value>{
};

Важно отметить, что, поскольку мы не определили TemplateVectorCode<T, false>, компилятор выдаст ошибку компиляции, если вы попытаетесь использовать функтор с типом класса T, который не является производным от типа V.Это означает, что вы можете работать с одним и тем же кодом в одном месте без необходимости писать несколько версий.

(если я облажался с частичной специализацией шаблона, кто-то, пожалуйста, отредактируйте его. Мне нужно лечь спать).

...