2008-10-01 52 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; 
    } 
} 
相关问题