Позволять Base
а также Derived
быть классы с членами данных:
class Base {
public:
Base(int i):f(i) { }
virtual void print() { cout << "base " << f << endl; }
int f;
};
class Derived: public Base {
public:
Derived(int i):Base(0),g(i) { }
void print() { cout << "derived " << g << endl; }
int g;
};
Теперь создайте несколько экземпляров Base
а также Derived
на кучу и хранить их в boost::ptr_vector
:
int main(int argc, char *argv[])
{
boost::ptr_vector<Base> v;
v.push_back(new Derived(1));
v.push_back(new Base(2));
v.push_back(new Base(3));
v.push_back(new Derived(4));
распечатать все объекты:
for (std::size_t i(0); i != v.size(); ++i)
v[i].print();
затем разверните и снова напечатайте:
std::reverse(v.begin(), v.end());
for (std::size_t i(0); i != v.size(); ++i)
v[i].print();
}
Эта программа печатает:
derived 1
base 2
base 3
derived 4
derived 1
base 3
base 2
derived 4
std::reverse()
на boost::ptr_vector
звонки std::iter_swap()
который в свою очередь вызывает std::swap
который меняет элементы, создавая временную копию.
Тем не менее, временная копия нарезает производные объекты. Как видите, int g
из Derived
объекты 1 и 4 не поменялись местами, так что объекты разбиваются после обмена.
Такое поведение меня озадачивает. не boost::ptr_vector
контейнер, чтобы избежать именно такой проблемы?
Что мне нужно здесь, это конструктор виртуальных копий, который не существует в C ++.
Как я могу обойти это? Нужно ли реализовать виртуальную функцию подкачки для Base
, так что виртуальная диспетчеризация вызывает другую функцию-член подкачки Derived
?
РЕДАКТИРОВАТЬ: зачем копировать объекты в первую очередь? Поскольку вектор хранит только указатели, изменение его должно быть обменом указателей, а не объектов, на которые указывают!
Есть ли функция, которая делает это?
Повышение-х ptr_vector
Класс содержит функции-члены, работа которых заключается в манипулировании указателями. Но публичный интерфейс в значительной степени скрывает тот факт, что вектор внутренне хранит указатели. Идея состоит в том, чтобы создать что-то, что ведет себя так, как если бы оно содержало объекты напрямую, но внутренне хранило указатели, чтобы избежать нарезки, когда вы помещаете объект в контейнер. Но если вы скопируете объект из контейнера в объект базового типа, он будет разрезан. Таким образом, вы не должны вызывать такие функции на ptr_vector
s.
К сожалению, это означает, что, прежде чем применять какой-либо алгоритм к ptr_vector
, вы должны точно понимать, что он делает.
Один из возможных способов обойти это использовать
std::reverse(v.base().begin(), v.base().end());
вместо. Он переворачивает указатели вместо самообращающихся итераторов.