Getting a Vector<Derived*> into a Function That Expects a Vector<Base*>

Getting a vectorDerived* into a function that expects a vectorBase*

vector<Base*> and vector<Derived*> are unrelated types, so you can't do this. This is explained in the C++ FAQ here.

You need to change your variable from a vector<Derived*> to a vector<Base*> and insert Derived objects into it.

Also, to avoid copying the vector unnecessarily, you should pass it by const-reference, not by value:

void BaseFoo( const std::vector<Base*>& vec )
{
...
}

Finally, to avoid memory leaks, and make your code exception-safe, consider using a container designed to handle heap-allocated objects, e.g:

#include <boost/ptr_container/ptr_vector.hpp>
boost::ptr_vector<Base> vec;

Alternatively, change the vector to hold a smart pointer instead of using raw pointers:

#include <memory>
std::vector< std::shared_ptr<Base*> > vec;

or

#include <boost/shared_ptr.hpp>
std::vector< boost::shared_ptr<Base*> > vec;

In each case, you would need to modify your BaseFoo function accordingly.

C++ casting a std::vectorDerived* to std::vectorBase ...?

No, that is not possible. There is no relationship between std::vector<Base> and std::vector<Derived>.

In other words: std::vector<Derived> is NOT derived from std::vector<Base>.

Conversion from STL vector of subclass to vector of base class

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.

I want a vector of derived class pointers as base class pointers

There is a copy constructor for a std::vector but it requires you to copy the exact same type of vector. Fortunately, there is another constructor which takes a pair of iterators and adds all the elements in the range, so you can do this:

vector<Animal*> animals(dogs.begin(),dogs.end());

This creates a new vector of Animal pointers by iterating through each Dog pointer. Each Dog pointer is converted to an Animal pointer as it goes.

Here is a more complete example (using C++11):

#include <vector>

struct Animal { };

struct Dog : Animal { };

struct Cat : Animal { };

struct Bird : Animal { };

int main(int,char**)
{
Dog dog1, dog2;
Cat cat1, cat2;
Bird bird1, bird2;
std::vector<Dog *> dogs = {&dog1,&dog2};
std::vector<Cat *> cats = {&cat1,&cat2};
std::vector<Bird *> birds = {&bird1,&bird2};
std::vector<std::vector<Animal *>> all_animals = {
{dogs.begin(),dogs.end()},
{cats.begin(),cats.end()},
{birds.begin(),birds.end()}
};
}

How to pass a vector of a Child class in to a function expecting a vector of Parent class?

This is not possible in C++, this requires a feature called covariance.

Even if type A is a subclass of type B, type X<A> is completely unrelated to type X<B>

Thus you cannot pass std::vector<UPSEvent> to a function expecting std::vector<Event>, since they are unrelated types. Even pass by reference/pointer will not work.

There are two ways to get around this.

One would be to make both vectors hold pointers to Event, then they would have identical types.

The other, would be to make the function a template function, as Daniel suggests.

You would need to fix the signature as well, as billz points out.

Store derived class objects in base class variables

What you are seeing is Object Slicing.

You are storing object of Derived class in an vector which is supposed to store objects of Base class, this leads to Object slicing and the derived class specific members of the object being stored get sliced off, thus the object stored in the vector just acts as object of Base class.

Solution:

You should store pointer to object of Base class in the vector:

vector<Base*> 

By storing a pointer to Base class there would be no slicing and you can achieve the desired polymorphic behavior as well.

Since you ask for a C++ish way of doing this, the right approach is to use a suitable Smart pointer instead of storing a raw pointer in the vector. That will ensure you do not have to manually manage the memory, RAII will do that for you automatically.

candidate function not viable: no known conversion from std::vectorderived to std::vectorbase

What about

template <typename T>
void print(std::vector<T> const & z) {
for(auto const & i:z) {
print(i);
}
}

instead of

void print(std::vector<A<K,V>> z) {
for(auto& i:z) {
print(i);
}
}

?

I mean: you cannot have an implicit conversion from std::vector<B> to std::vector<A<K, T>> but you can manage the content of a generic std::vector<T> (generic T) and obtain (in case) implicit conversion from T elements to A<K, T> (if T is a derived type).

If you want, you can add an std::enable_if to enable the template print function only if T is derived from A<K, T>.

-- EDIT --

The OP asked

How can I use std::enable_if to enable the template print function to operate only on objects derived from A?

There are many ways; see, by example, the Caleth's answer with an additional template types and a std::enable_if to activate it.

But I prefer the returned value activated by std::enable_if.

Something as (caution: code not tested)

template <typename T>
typename std::enable_if<std::is_base_of<A<K, V>, T>::value>::type
print(std::vector<T> const & z)
{ for(auto const & i:z) print(i); }

If you can use C++14 you can simplify a little (using std::enable_if_t<> instead of typename std::enable_if<>::type)

template <typename T>
std::enable_if_t<std::is_base_of<A<K, V>, T>::value>
print(std::vector<T> const & z)
{ for(auto const & i:z) print(i); }

and using C++17 a little more (std::is_base_of_v<> instead of `std::is_base_of<>::value)

template <typename T>
std::enable_if_t<std::is_base_of_v<A<K, V>, T>>
print(std::vector<T> const & z)
{ for(auto const & i:z) print(i); }


Related Topics



Leave a reply



Submit