让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
通过创建临时副本来交换项目。
但是,临时副本确实对派生对象进行切片。如您所见,Derived
对象 1 和 4 的int g
没有交换,因此对象在交换后被破坏。
这种行为让我感到困惑。boost::ptr_vector
不是为了避免这种问题的容器吗?
我在这里需要的是一个虚拟复制构造函数,它C++中不存在。
我该如何解决此问题?我是否需要为Base
实现一个虚拟交换函数,以便虚拟调度调用Derived
的另一个交换成员函数?
编辑:为什么要首先复制对象?由于向量只存储指针,因此反转它应该是指针的交换,而不是指向的对象!有没有一个函数可以做到这一点?
Boost的ptr_vector
类包含成员函数,其工作是操作底层指针。但是公共接口在很大程度上隐藏了向量内部存储指针的事实。这个想法是生成一些东西,它的行为就好像它直接包含对象一样,但在内部存储指针以避免在将对象放入容器时切片。但是,如果将对象从容器复制到基类型的对象中,则它将切片。因此,您一定不能在 ptr_vector
s 上调用此类函数。
不幸的是,这意味着在将任何算法应用于ptr_vector
之前,您需要准确了解它的作用。
一种可能的解决方法是使用
std::reverse(v.base().begin(), v.base().end());
相反。它反转指针而不是自定向迭代器。