如何在不公开使用的容器的情况下公开迭代器?

时间:2020-03-06 14:58:11  来源:igfitidea点击:

我已经使用Cfor一段时间了,回到C ++令人头疼。我正在尝试将我的一些实践从Cwithme升级到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吗?我希望仅依赖于迭代器,而不是依赖于实现容器...

解决方案

这应该做我们想要的:

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

从加速的C ++:

Whenever you have a type, such as vector<T>, that depends on a template parameter, and you want to use a member of that type, such as size_type, that is itself a type, you must precede the entire name by typename to let the implementation know to treat the name as a type.

我不确定"不公开公开std :: vector"的含义,但实际上,我们可以像这样定义typedef:

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

我们将可以稍后更改这些typedef,而无需用户注意任何事情。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

顺便说一句,如果我们希望类充当容器,则最好公开一些其他类型:

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;

如果班级需要:

typedef typename std::vector<T>::const_pointer const_pointer;
 typedef typename std::vector<T>::const_reference const_reference;

我们将在这里找到所有这些typedef的含义:向量上的STL文档

编辑:添加了typename,如注释中所建议

我们可能会发现以下文章很有趣,因为它恰好解决了我们已发布的问题:关于C ++中的面向对象编程和通用编程之间的紧张关系以及如何进行类型擦除

我之前已经做过以下工作,以便获得独立于容器的迭代器。这可能是过高的,因为我还可以使用API​​,在该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;
    }
}