Reputation: 1296
#include <iostream>
#include <vector>
using namespace std;
class Base {
public:
virtual ~Base(){}
};
class Deriv : public Base {
public:
virtual ~Deriv(){}
};
void f(Base *){
cout << "f(Base *)" << endl;
}
void f(vector<Base *>){
cout << "f(vector<Base *>)" << endl;
}
int main(int argc, const char *argv[])
{
Deriv *d = new Deriv;
vector<Deriv *> v;
v.push_back(d);
f(d); // works
//f(v); // does not compile
return 0;
}
The first f() works, but the second gives a compile time error:
f(vector<Deriv *>) not found.
My question: is there a way to make it work: some kind of polymorphism with vectors?
Upvotes: 1
Views: 2254
Reputation: 361352
Base
and Deriv
are covariant types, but std::vector<Base*>
and std::vector<Deriv*>
are not covariant types.
When X
is an object of a covariant type B
, you can assign object of any type D
derive from B
, to X
. That is what happens in your first case.
Upvotes: 1
Reputation: 234424
The property you want is called covariance. And the answer is no, you cannot do this: vectors are not covariant.
The canonical example of why this is not allowed goes like this:
class Deriv2 : public Base {
public:
virtual ~Deriv2(){}
};
void f(vector<Base *>& v){
v.push_back(new Deriv2); // oops, just pushed a Deriv2 into a vector of Deriv
}
If you're not adding elements to the vector, you can just pass a pair of input iterators. Passing output iterators would not work either.
template <typename InputIterator>
void f(InputIterator first, InputIterator last);
f(v.begin(), v.end());
Upvotes: 4
Reputation: 965
You should write this in main
Deriv *d = new Deriv;
vector<Base *> v; // Correction
v.push_back(d);
You can still push the Derived
objects into container and f()
works fine.
Template solution is good as well:
template <typename T>
void f(std::vector<T>);
Upvotes: 1
Reputation: 33655
AFAIK not the way you would like (vector<Base*>
is a fundamentally different type to vector<Deriv*>
).
Here's one alternative approach - this is of course a general algorithm
template <typename Iterator>
void f(Iterator begin, Iterator end)
{
// now do stuff...
}
To call
f(v.begin(), v.end());
Upvotes: 3