2011-03-28 95 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 *>是否具有相同的內部結構」在其他實現中是正確的。