2011-03-28 92 views
5

可以将STL容器从Base类型转换为Derived类型吗?例如,我有两个向量。第一个是基类的类型,第二个是Derive类的类型。将基类型的STL容器转换为派生类型可以吗?

class Base 
{ 
// Code 
}; 

class Derive : public Base 
{ 
// Code 
}; 

使用

vector<Base*>* vec_base = new vector<Base*>; 

    // Add some Derive type data to vec_base 

    vector<Derive*>* vec_derive = (vector<Derive*>*)(vec_base); 

    // Using elements as Derive pointers. Works fine. 

这是好吗? (它工作正常,但我想获得一些关于此的评论)。非常感谢你。

编辑:根据答案更新。如果我仔细地使用该向量,并且不会使用多重继承,并且不会插入除导出类型之外的其他对象,那么可以吗? (我想,它不是)

非常感谢你的答案。

+0

Re:update - 没有使用类似std :: transform的东西,你可以做的任何事情都将使它使用reinterpret_cast以外的任何其他类型,这不是你正在寻找的 – Flexo 2011-03-28 14:34:58

+0

@awoodland因此,reinterpret_cast甚至不好多态类型?我的意思是,即使我100%确定“我知道矢量reinterpret_cast的确切类型”在这种情况下是未定义的? – Morpheus 2011-03-28 14:46:59

+1

reinterpret_cast在std :: vector上绝对不好,问题是没有(便携式,标准化的)理由假设std :: vector 和std :: vector 的内存布局是兼容的,这样就可以工作。 – Flexo 2011-03-28 14:50:09

回答

8

这绝对不是好的,并且是c样式转换蒙板错误的例子之一。 “它适用于我”并不代表在这种情况下明确定义的行为。

如果你真的想这样做,我建议:

#include <vector> 
#include <algorithm> 
#include <iterator> 

using namespace std; 

class Base 
{ 
// Code 
virtual ~Base(); 
}; 

class Derrive : public Base 
{ 
// Code 
}; 

Derrive *convert(Base * in) { 
    // assert here? 
    return dynamic_cast<Derrive*>(in); 
} 

int main() { 
    vector<Base*>* vec_base = new vector<Base*>; 

    // Add some Derrive type data to vec_base 

    vector<Derrive*>* vec_derrive = new vector<Derrive*>; 

    transform(vec_base->begin(), vec_base->end(), back_insert_iterator<vector<Derrive*> >(*vec_derrive), convert); 
} 
+0

这是很好的方式。非常感谢 – Morpheus 2011-03-28 14:34:35

+2

这是一个耻辱dynamic_cast不是一个函数,因为那么你可能不需要convert函数来包装dynamic_cast。 – Flexo 2011-03-28 14:36:39

+0

当您使用vec_derrive时,请在使用它之前检查每个成员是否为空。如果任何dynamic_cast失败,则会在您的向量中获得空条目。 – Tim 2011-03-28 14:47:09

0

号这不会很好地工作。

假设我有Derrive2派生自Base。我可以把它放在STL容器中,但它不会安全地投射到Derrive

+0

好吧,说我会小心使用该矢量,并不会将Derrived2类型放入矢量中。现在,可以吗? – Morpheus 2011-03-28 14:27:36

+0

仍然是一个坏主意。 – 2011-03-28 14:28:04

+0

@Morpheus不,它不好 - 矢量类型仍然没有关系。 – 2011-03-28 14:32:25

1

这并不好。模板类型不同T s为不相关的类型(尽管他们都表示std::vector,使用C样式转换只是让你得逞的未定义行为。

如果它似乎对现在的工作,认为自己是不幸的,它没有崩溃

如果你知道向量中的所有项都是派生类,那么只需要将向量指向派生对象就可以了,如果你不知道,那么演员阵容就不安全

2

你正在做一个C风格的演员阵容,它本质上是做一个reinterpret_cast,它告诉编译器“从现在开始对待x就像y,并且相信我它RKS”。所以它肯定会编译,但不是一个好主意。这里没有类型安全,并且可能在某些时候有效,但在其他时间会崩溃。

你能做什么,而不是:

for (unsigned int i=0; i < vec_base->length(); i++) 
{ 
    Derrive* d = dynamic_cast<Derrive*> (vec_base[i]); 
    if (d) { 
    // this element is a Derrive instance, so we can treat it like one here 
    } 
    // else, skip it, log an error, throw an exception, whatever, 
    // this element in the vector is not of type Derrive 
} 
+0

是的,应该是这样。但是我不能让用户使用dynamic_cast,因为它处于关键路径中。我想,通过强制编译器转换为Derrive类型,它应该可以工作 – Morpheus 2011-03-28 14:38:22

0

更安全的方式做到这一点是使用的std ::变换。

但是,由于在std :: list的实现中,T = Base *或T = Derived *的行为方式相同(都具有相同的大小),所以列表的内部结构与列表相同。因此,它是可以做到下面的技巧:

vector<Derived*> vector2 = *(reinterpret_cast< vector<Derived*>* >(&vector1)); 

注: 我的答案是信息,请坚持使用的std ::变换方法。我不确定在STDC++实现中,除了GCC之外,向量的行为方式是否相同,即。我不确定断言“列表< Base *>和列表< Derivated *>是否具有相同的内部结构”在其他实现中是正确的。