c ++ std :: copy类型转换为派生类可能吗?

时间:2010-08-18 15:56:45

标签: c++ list vector copy

我很确定没有办法明确地做到这一点,但我想问一下,如果有更好的方法。我有一个基类A和一个派生类B,现在我有一个指向B *的st * :: A *列表,我希望将这个A *列表复制到一个std :: vector of B *基本上我想这样做:

std::list<A*> aList = someObject.getAs();
std::vector<B*> bVec = std::vector<B*>(aList.begin(), aList.end());

我很确定这应该在列表和向量相同时编译(例如两者都是A *),但是因为在这种情况下A *是B *的基类我不能做这样,因为我必须明确地进行类型转换,例如:

std::list<A*> aList = someObject.getAs();
std::vector<B*> bVec;
bVec.reserve(aList.size());
std::list<A*>::iterator it = aList.begin();
for(it; it!=aList.end(); ++it)
{
   B* b = static_cast<B*>(*it);
   bVec.push_back(b);
}

有没有比我的第二种方法更优雅的方式,还是我必须这样做?

4 个答案:

答案 0 :(得分:15)

隐式转换是不安全的,所以你必须明确它。将某种转换应用于序列的标准算法是std::transform,您可以使用它来填充空容器,如下所示:

struct A {};
struct B : A {};

template <typename From, typename To>
struct static_caster
{
    To* operator()(From* p) {return static_cast<To*>(p);}
};

std::list<A*> a;
std::vector<B*> b;
std::transform(a.begin(), a.end(), std::back_inserter(b), static_caster<A,B>());

答案 1 :(得分:7)

定义一个仿函数来进行投射,例如。

struct Downcast
{
    B* operator() ( A* a ) const
    {
        return static_cast< B* >( a );
    }
};

然后使用std::transform代替std::copy,即

bVec.resize(aList.size());
std::transform( aList.begin(), aList.end(), bVec.begin(), Downcast() );

注意你也可以

std::vector<B*> bVec;
std::transform( aList.begin(), aList.end(), std::back_inserter( bVec ), Downcast() );

在这种情况下bVec会根据需要增长,但我更喜欢第一种方法,绝对确保内存分配一次完成。正如@Mike Seymour指出的那样,你可以在第二种情况下调用bVec.reserve( aList.size() )以确保一次分配。

答案 2 :(得分:2)

使用转换:

#include <cstdlib>
#include <vector>
#include <algorithm>
using namespace std;

class A
{
};
class B : public A
{
};

A* get_a() { return new B; }

B* make_b(A* a) { return static_cast<B*>(a); }

int main()
{
    vector<A*> a_list;
    vector<B*> b_list;

    generate_n(back_inserter(a_list), 10, get_a);
    transform(a_list.begin(), a_list.end(), back_inserter(b_list), make_b);

    return 0;
}

答案 3 :(得分:1)

您可以使用迭代器适配器方法,但如果您这样做,我建议您正确执行此操作。要么你需要覆盖使迭代器成为“迭代器”的所有东西,要么使用Boost.Iterator,这是一个让这些事情变得更容易的库。

您将使用的另一种方法是创建一个仿函数并使用std :: transform而不是std :: copy。在我看来,这似乎是一种更容易的方法。如果你使用的是C ++ 0x编译器,你甚至可以使用lambda。

编辑:建议使用适配器的人拉了他的答案,所以第一段可能没有多大意义。它在向量迭代器周围使用了一个包装器,它返回了B *而不是A *,但它遗漏了大量正确执行它的工作。