I am wondering if it is possible to convert a vector of derived class values to a vector of base class values. Specifically I want to be able to pass a vector of base class objects to a function whose formal parameters takes a vector of base class. It does not appear to be possible directly as the following code example produces an error (using 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: error: conversion from ‘std::vector<B, std::allocator<B> >’ to non-scalar type ‘std::vector<A, std::allocator<A> >’ requested
I would like to be able to be able to call function without having to define a new vector with elements of type A, inserting my elements of type B or changing to a vector of pointers.
No, it is not. vector<B>
is not derived from vector<A>
, regardless of the fact that B
is derived from A
. You will have to change your function somehow.
A more idiomatically C++ approach might be to template it and have it take a pair of iterators - this is why the various standard library functions (<algorithm>
etc) work that way, because it separates the implementation of the algorithm from the kind of thing it's operating on.
Sometimes there are ways around this. Take a loot at Boost and some of the template meta-programming packages they have or use. Specifically I'd look at is_base_of for these kinds of purposes combined with partial template specialization.
For instance, if you wish to do some template magic trickery:
template<typename T, bool Allowed>
struct TemplateVectorCode;
You make a forward declaration of a templated class. Then you make a specialization with a "true" boolean value:
template<typename T> struct TemplateVectorCode<T, true>{
void operator(const std::vector<T>& myVector) const{ //definition in here }
};
Finally you use that with is_base_of
to only instantiate instances of your template functor in the following manner:
template<typename T, typename Base>
struct MyFunction : TemplateVectorCode<T, boost::is_base_of<Base,T>::value>{
};
The important point to note is that since we have not defined a TemplateVectorCode<T, false>
the compiler will throw a compile error if you attempt to use your functor with a class type T
that does not derive from the type V
. That means you can work with the same code in one place without having to write multiple versions of it.
(if I screwed up the partial template specialization, someone please edit it. I need to go to bed.)