8

BaseDerived成为具有数据成员的类:

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它们存储在 a 中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()onboost::ptr_vector调用std::iter_swap()又调用std::swapwhich 通过创建临时副本来交换项目。

但是,临时副本确实对 Derived 对象进行了切片。如您所见,int g对象Derived1 和 4 的没有交换,因此交换后对象已损坏。

这种行为让我很困惑。容器不boost::ptr_vector就是要避免这种问题吗?

我在这里需要的是一个虚拟复制构造函数,它在 C++ 中不存在。

我该如何解决这个问题?我是否需要为 实现一个虚拟交换函数Base,以便虚拟调度调用另一个交换成员函数Derived

编辑:为什么首先要复制对象?由于向量只存储指针,因此反转它应该是指针的交换,而不是指向的对象!有没有这样做的功能?

4

2 回答 2

1

Boost 的ptr_vector类包含成员函数,其工作是操作底层指针。但是公共接口很大程度上隐藏了向量内部存储指针的事实。这个想法是产生一些表现得好像它直接包含对象但在内部存储指针以避免在将对象放入容器时切片的东西。但是如果你将一个对象从容器中复制到一个基本类型的对象中,那么它就会切片。所以你不能在ptr_vectors 上调用这样的函数。

不幸的是,这意味着在将任何算法应用于 a 之前ptr_vector,您需要准确了解它的作用。

于 2014-07-19T16:34:04.597 回答
0

一种可能的解决方法是使用

std::reverse(v.base().begin(), v.base().end());

反而。它反转指针而不是自间接迭代器。

于 2014-07-19T16:42:45.260 回答