std :: вектор и полиморфизм - PullRequest
       1

std :: вектор и полиморфизм

1 голос
/ 13 сентября 2011
#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;
}

Первый f () работает, но второй дает ошибку времени компиляции:

f(vector<Deriv *>) not found.

Мой вопрос: есть ли способ заставить его работать: какой-то полиморфизм с векторами?

Ответы [ 4 ]

4 голосов
/ 13 сентября 2011

Свойство, которое вы хотите, называется ковариацией.И ответ «нет», вы не можете сделать это: векторы не являются ковариантными.

Канонический пример того, почему это не разрешено, выглядит следующим образом:

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
}

Если вы не добавляетеэлементы вектора, вы можете просто передать пару input итераторов.Передача выходных итераторов также не будет работать.

template <typename InputIterator>
void f(InputIterator first, InputIterator last);

f(v.begin(), v.end());
3 голосов
/ 13 сентября 2011

AFAIK не так, как вы хотели бы (vector<Base*> принципиально отличается от vector<Deriv*>).

Вот один альтернативный подход - это, конечно, общий алгоритм

template <typename Iterator>
void f(Iterator begin, Iterator end)
{
  // now do stuff...
}

Для звонка

f(v.begin(), v.end());
1 голос
/ 13 сентября 2011

Base и Deriv являются ковариантными типами, но std::vector<Base*> и std::vector<Deriv*> не являются ковариантными типами.

Когда X является объектом ковариантного типа B, вы можете назначить объект любого типа D, производного от B, X. Вот что происходит в вашем первом случае.

1 голос
/ 13 сентября 2011

Вы должны написать это в основном

  Deriv *d = new Deriv;
  vector<Base *> v;  // Correction
  v.push_back(d);

Вы все еще можете помещать объекты Derived в контейнер, и f() работает нормально.

Шаблонное решение также хорошо:

template <typename T>
void f(std::vector<T>);
...