torbatamas
torbatamas

Reputation: 1296

std::vector and polymorphism

#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

Answers (4)

Sarfaraz Nawaz
Sarfaraz Nawaz

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

R. Martinho Fernandes
R. Martinho Fernandes

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

Werolik
Werolik

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

Nim
Nim

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

Related Questions