2009-07-24 48 views
8

我有一個基類,有幾個類擴展它。我有一些通用庫實用程序創建一個包含指向基類的指針的向量,以便任何子類都可以工作。我如何將矢量的所有元素轉換爲特定的子類?我可以將std :: vector <Animal*>轉換爲std :: vector <Dog*>而不必查看每個元素?

// A method is called that assumes that a vector containing 
// Dogs casted to Animal is passed. 
void myDogCallback(vector<Animal*> &animals) { 
    // I want to cast all of the elements of animals to 
    // be dogs. 
    vector<Dog*> dogs = castAsDogs(animals); 
} 

我天真的解決方案將是這個樣子:書面會放了一堆空指針到您的狗矢量當動物載體含有其它動物的專業化

// A method is called that assumes that a vector containing 
// Dogs casted to Animal is passed. 
void myDogCallback(vector<Animal*> &animals) { 
    // I want to cast all of the elements of animals to 
    // be dogs. 
    vector<Dog*> dogs; 
    vector<Animal*>::iterator iter; 
    for (iter = animals.begin(); iter != animals.end(); ++iter) { 
     dogs.push_back(dynamic_cast<Dog*>(*iter)); 
    } 
} 
+1

重複:http://stackoverflow.com/questions/902667/stl-container-assignment-和 - 常量指針 – GManNickG 2009-07-24 03:39:32

+4

這是不是很愚蠢 - 請注意,他不是從`矢量`複製到`矢量`,但反過來! – 2009-07-24 03:45:21

回答

0

您的代碼。

vector<Dog*> dogs; 
vector<Animal*>::iterator iter; 
Dog* dog; 

for(iter = animals.begin(); iter != animals.end(); ++iter) 
{ 
    dog = dynamic_cast<Dog*>(*iter); 
    if(dog) 
    { 
    dogs.push_back(dog); 
    } 
} 
0

通常使用dynamic_cast進行向下轉換不是很好。你應該重構你的代碼,這樣你就不需要使用明確的向下轉換。

有關更多信息,請參見CPP FAQ lite

UPD此外,請參閱Stroustrup page(搜索 「爲什麼我不能指定一個矢量到矢量?」)

10

你可以使用std::transform。它仍然採用for()內部,但你會得到兩個字符串實現:

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

struct Animal { virtual ~Animal() {} }; 
struct Dog : Animal { virtual ~Dog() {} }; 

template<typename Target> 
struct Animal2Target { Target* operator()(Animal* value) const { return dynamic_cast<Target*>(value); } }; 

void myDogCallback(vector<Animal*> &animals) { 
{ 
    vector<Dog*> dogs; 
    transform(animals.begin(), animals.end(), dogs.begin(), Animal2Target<Dog>()); 
}
0

有兩個選項。最簡單的方法是使用remove_copy_if之類的東西。我無法解釋爲什麼他們稱之爲這個,但它將元素從一個容器複製到另一個容器中,不滿足滿足謂詞。這裏的基本思想(未經測試):

struct IsDog : unary_function < Animal *, bool > { 
    bool operator()(Animal * animal) const { 
    return dynamic_cast <Dog*> (animal); 
    } 
}; 

void foo (vector<Animal*> animals) { 
    vector<Dog*> dogs; 
    std::remove_copy_if (animals.begin() 
    , animals.end() 
    , back_inserter (dogs) 
    , std::not1 (IsDog())); // not1 here negates the result of IsDog! 


    // dogs now contains only animals that were dogs 

}

我想一個方式來看待remove_copy_if是把它作爲copy_unless

另一種方法是,如果您僅將代碼基於迭代器,則將包含矢量< Animal *>的迭代器包含爲只返回集合中的狗。這裏的關鍵優勢在於,您仍然只有一個容器,但是當然,您會付出更多的代價,因爲您的算法會瀏覽整個動物集合。

class dog_iterator // derive from std::iterator probably with bidirectinoal tag 
{ 
private: 
    vector<Animals*>::iterator getNextDogIter (vector<Animals*>::iterator iter) { 
    while (iter != m_end) { 
     if (0 != dynamic_cast<Dog*> (*iter)) { 
     break; 
     } 
     ++iter; 
    } 
    return iter; 
    } 

public: 
    dog_iterator (vector<Animals*>::iterator iter, vector<Animals*>::iterator end) 
    : m_end (end) 
    , m_iter (getNextDogIter (iter)) 
    { 
    } 

    // ... all of the usual iterator functions 

    dog_iterator & operator++() 
    { 
    // check if m_iter already is at end - otherwise: 
    m_iter = getNextDogIter (m_iter + 1); 
    return *this; 
    } 
    // ... 
}; 

這很粗糙,但我希望它能向你展示基本原理。

0

如果你說你能保證每一個元素是一個真正的狗那麼就static_cast

void myDogCallback(vector<Animal*> &animals) { 

    const vector<Animal*>::size_type numAnimals = animals.size(); 

    vector<Dog*> dogs; 
    dogs.reserve(numAnimals); 

    for (vector<Animal*>::size_type i = 0; i < numAnimals; ++i) { 
     dogs.push_back(static_cast<Dog*>(animals[i])); 
    } 
} 

我通常總是從人們下意識的反應,這是不好的,你應該總是使用但實際上,如果你可以對這種類型做出保證,那麼它是完全安全的,而且IMO是一個明智的做法。

此外,您的保證意味着新的矢量具有相同的大小,因此保留相同的空間以避免在每個push_back中進行任何分配。作爲一種替代迴路我使用的索引僅僅是因爲我一直認爲使用索引必須大於一個迭代更快的迭代,但是這可能是廢話:)

0

當你能保證,你std::vector<Animal*>只包含Dog*可以使用reinterpret_cast

0

混合的std::transform方法與static_cast(因爲你有一定的安全性)可能看起來像:

std::transform(animals.begin(), animals.end(), 
       std::back_insert_iterator<std::vector<Dog*>>(dogs), 
       [](auto ptr) { return static_cast<Dog*>(ptr); }); 
相關問題