2008-10-01 93 views
22

我一直在使用C#一段時間,而回到C++是一件令人頭疼的事情。我試圖從C++中將我的一些練習與C++一起獲得,但是我發現了一些阻力,我很樂意接受你的幫助。如何在不暴露容器的情況下公開迭代器?

我想揭露迭代器像這樣的類:

template <class T> 
class MyContainer 
{ 
public: 
    // Here is the problem: 
    // typedef for MyIterator without exposing std::vector publicly? 

    MyIterator Begin() { return mHiddenContainerImpl.begin(); } 
    MyIterator End() { return mHiddenContainerImpl.end(); } 

private: 
    std::vector<T> mHiddenContainerImpl; 
}; 

上午我試圖在東西是不是有問題?我應該只是typedef std :: vector < T> :: iterator?我希望對剛剛取決於迭代器,而不是實現容器...

+0

同樣看到這個[問題](http://stackoverflow.com/questions/127009/returning-an-any-kind-of-input-iterator-instead-of-a-vectoriterator-or-a -listit) – 2008-10-01 12:11:40

回答

2

這應該做你想要什麼:

typedef typename std::vector<T>::iterator MyIterator; 

Accelerated C++

只要你有一個類型,例如vector<T>,它取決於模板參數,並且您想要使用該類型的成員(如size_type),該成員本身就是一個類型,您必須在整個名稱前面加上typename以讓知道該實現將名稱視爲一種。

1

我不確定你的意思是「未暴露的std ::矢量公開」的話,但事實上,你可以定義你的typedef這樣的:

typedef typename std::vector<T>::iterator iterator; 
typedef typename std::vector<T>::const_iterator const_iterator; // To work with constant references 

您將能夠改變這些類型定義後來未經用戶察覺什麼...

順便說一句,它被認爲是很好的做法,如果你想你的類表現爲一個容器,也暴露出一些其他類型:

typedef typename std::vector<T>::size_type size_type; 
typedef typename std::vector<T>::difference_type difference_type; 
typedef typename std::vector<T>::pointer pointer; 
typedef typename std::vector<T>::reference reference; 

,如果需要,通過你的類:

你會發現所有這些類型定義在這裏的含義是:STL documentation on vectors

編輯:增加了typename如意見提出

+0

也許我對此有點過分了,但是我想讓typedef公開我正在使用stl iterators,而不是實際的容器。如果我做typedef std :: vector :: iterator迭代器,那麼人們可以做std :: vector <ínt> :: iterator iter = example.Begin();. (續) – Statement 2008-10-01 11:26:32

+0

儘管起初這看起來並不是問題,但想象一下,如果我將班級的內部實現更改爲使用列表來代替。客戶端代碼會中斷。使用與許多不同容器一起工作的通用迭代器可以解決這個問題。問題是我沒有找到辦法做到這一點。 – Statement 2008-10-01 11:27:51

2

我已經做過以下所以t我得到了一個獨立於容器的迭代器。這可能是過度殺傷,因爲我也可以使用API​​調用者傳入的vector<T*>&應該填充所有元素,然後調用者可以直接從矢量迭代。

template <class T> 
class IterImpl 
{ 
public: 
    virtual T* next() = 0; 
}; 

template <class T> 
class Iter 
{ 
public: 
    Iter(IterImpl<T>* pImpl):mpImpl(pImpl) {}; 
    Iter(Iter<T>& rIter):mpImpl(pImpl) 
    { 
     rIter.mpImpl = 0; // take ownership 
    } 
    ~Iter() { 
     delete mpImpl; // does nothing if it is 0 
    } 
    T* next() { 
    return mpImpl->next(); 
    } 
private: 
    IterImpl<T>* mpImpl; 
}; 

template <class C, class T> 
class IterImplStl : public IterImpl<T> 
{ 
public: 
    IterImplStl(C& rC) 
    :mrC(rC), 
    curr(rC.begin()) 
    {} 
    virtual T* next() 
    { 
    if (curr == mrC.end()) return 0; 
    typename T* pResult = &*curr; 
    ++curr; 
    return pResult; 
    } 
private: 
    C& mrC; 
    typename C::iterator curr; 
}; 


class Widget; 

// in the base clase we do not need to include widget 
class TestBase 
{ 
public: 
    virtual Iter<Widget> getIter() = 0; 
}; 


#include <vector> 

class Widget 
{ 
public: 
    int px; 
    int py; 
}; 

class Test : public TestBase 
{ 
public: 
    typedef std::vector<Widget> WidgetVec; 

    virtual Iter<Widget> getIter() { 
     return Iter<Widget>(new IterImplStl<WidgetVec, Widget>(mVec)); 
     } 

    void add(int px, int py) 
    { 
     mVec.push_back(Widget()); 
     mVec.back().px = px; 
     mVec.back().py = py; 
    } 
private: 
    WidgetVec mVec; 
}; 


void testFn() 
{ 
    Test t; 
    t.add(3, 4); 
    t.add(2, 5); 

    TestBase* tB = &t; 
    Iter<Widget> iter = tB->getIter(); 
    Widget* pW; 
    while (pW = iter.next()) 
    { 
     std::cout << "px: " << pW->px << " py: " << pW->py << std::endl; 
    } 
} 
相關問題