Domanda

Sto usando C # da un po 'di tempo, e tornare a C ++ è un mal di testa. Sto cercando di ottenere alcune delle mie pratiche da C # con me a C ++, ma sto trovando un po 'di resistenza e sarei felice di accettare il tuo aiuto.

Vorrei esporre un iteratore per una classe come questa:

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;
};

Sto provando a qualcosa che non è un problema? Dovrei solo digitare std :: vector & Lt; T & Gt; :: iteratore? Spero solo di dipendere dall'iteratore, non dal contenitore di implementazione ...

È stato utile?

Soluzione

Potresti trovare interessante il seguente articolo in quanto risolve esattamente il problema che hai pubblicato: On the Tension Tra programmazione orientata agli oggetti e generica in C ++ e che tipo di cancellazione può fare al riguardo

Altri suggerimenti

Ho già fatto quanto segue in modo da ottenere un iteratore indipendente dal contenitore. Questo potrebbe essere stato eccessivo poiché avrei anche potuto usare un'API in cui il chiamante passa in un vector<T*>& che dovrebbe essere popolato con tutti gli elementi e quindi il chiamante può semplicemente scorrere direttamente dal vettore.

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;
    }
}

Questo dovrebbe fare quello che vuoi:

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

Da C ++ accelerato :

  

Ogni volta che si dispone di un tipo, ad esempio vector<T>, che dipende da un parametro modello e si desidera utilizzare un membro di quel tipo, ad esempio size_type, che è esso stesso un tipo, è necessario precedere l'intero name by typename per far sapere all'implementazione di trattare il nome come un tipo.

Non sono sicuro di cosa intendi per " non esponendo std :: vector pubblicamente " ma in effetti, puoi semplicemente definire il tuo typedef in questo modo:

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

Sarai in grado di cambiare questi dattiloscritti in seguito senza che l'utente se ne accorga nulla ...

A proposito, è buona norma esporre anche alcuni altri tipi se vuoi che la tua classe si comporti come un contenitore:

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;

E se necessario per la tua classe:

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

Troverai il significato di tutti questi typedef qui: Documentazione STL sui vettori

Modifica: aggiunto typename come suggerito nei commenti

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top