2011-10-19 7 views
6

C'è tale codice:Wrap STL vettoriale e il cambiamento del comportamento del suo iteratore

#include <iostream> 
#include <vector> 

template <class T> 
class A{ 
public: 
    class iterator : public std::vector<T>::iterator{ 
    public: 
     T& operator*(){ 
      ?? 
     } 
    }; 

    iterator begin(){ 
     return v.begin(); // error 
    } 

    iterator end(){ 
     return v.end(); // error 
    } 

    void add(const T& elem){ 
     v.push_back(elem); 
    } 

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

int main() { 
    A<int> a; 
    a.add(2); 
    a.add(4); 
    for(A<int>::iterator it = a.begin(); it != a.end(); ++it){ 
     std::cout << *it << std::endl; 
    } 
    return 0; 
} 

Questo è un wrapper per std::vector con le mie funzioni aggiuntive. Vorrei utilizzare iteratore std::vector 's, ma voglio solo cambiare il comportamento di operator* per iteratore:

T& operator*(){ 
    // do some additional function 
    // normal behavior, return value of some element in vector 
      ?? 
} 

Come posso usare std::vector e il suo iteratore con la modificazione di soli operator*? Vorrei anche racchiudere funzioni come begin() e end() per l'iteratore, come avvolgerli correttamente?

EDIT:

Usando le punte dalle risposte a questo argomento, sono riuscito a risolvere il mio problema in questo modo:

#include <iostream> 
#include <vector> 

template <class T> 
class A { 
public: 

    class iterator : public std::vector<T>::iterator { 
    public: 

     iterator(typename std::vector<T>::iterator c) : std::vector<T>::iterator(c) { 
     } 

     T& operator*() { 
      std::cout << "Im overloaded operator*\n"; 
      return std::vector<T>::iterator::operator *(); 
     } 
    }; 

    iterator begin() { 
     return iterator(v.begin()); 
    } 

    iterator end() { 
     return iterator(v.end()); 
    } 

    void add(const T& elem) { 
     v.push_back(elem); 
    } 

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

int main() { 
    A<int> a; 
    a.add(2); 
    a.add(4); 

    for (A<int>::iterator it = a.begin(); it != a.end() ; ++it) { 
     std::cout << *it << std::endl; 
    } 
    return 0; 
} 

forse sarà utile per qualcuno.

+0

Sì. Ho letto male il codice. Non sono sicuro di come sia successo. –

risposta

3

Il wrapping di iteratori stdlib viene eseguito al meglio con gli adattatori iteratori. Questo compito è tutt'altro che banale e vi è la libreria Boost.Iterator per semplificare l'attività. Forse uno degli iteratori forniti risolve già il tuo problema.

Se avete intenzione di scrivere da soli (I davvero non consiglio questo), è necessario implementare il proprio iteratore e l'abbiano in essere costruibile da un vector::iterator, quindi sovraccaricare tutti gli operatori necessari per soddisfare i requisiti del concetto che il tuo nuovo iteratore modella. Anche ereditare da std::iterator per far funzionare i tratti. Non dimenticare di avere la variante const. This book ha un capitolo dedicato allo sviluppo dei propri iteratori. Anche ottenere una copia dello standard (C++ 03 o C++ 11, non importa molto qui). ti servirà.

+1

Ha anche bisogno di implementare un wrapper per 'std :: vector' se vuole usarlo in modo trasparente (che la sua domanda suggerisce). –

+0

@ BjörnPollex La classe sembra che abbia solo bisogno di un adattatore. La sua classe sembra non essere intesa come un modello completo di 'Sequence' ed esponendo' begin() 'e' end() 'dovrebbe richiedere solo iteratori. – pmr

1

Sfortunatamente, l'unico modo per farlo è scrivere un wrapper completo per std::vector e i suoi tipi di iteratore. Questo è un sacco di lavoro.

-1

Penso che la risposta qui sia più probabile che tu non sia il cambiare il comportamento dell'operatore * per un iteratore. L'overloading dell'operatore dovrebbe essere fatto solo nei casi in cui è estremamente intuitivo che chiunque leggendo il codice che utilizza l'operatore possa automaticamente sapere cosa sta succedendo. Un esempio di questo sarebbe se avessi una classe matrice e un operatore sovraccarico +. Quando qualcuno ti vede aggiungere due oggetti matrix insieme, possono facilmente sapere cosa sta succedendo.

In caso di dereferenziamento di un iteratore, tuttavia, non vi è una percezione intuitiva di quali saranno gli effetti collaterali aggiuntivi per la classe.

+1

Oh, cambiare il comportamento di 'operator *' può essere estremamente utile. Pensa 'trasformazione iteratori'. – pmr

1

Uno non eredita da std::vector<T>::iterator poiché non deve essere una classe. In alcune implementazioni questo è solo un typedef per T* e non è possibile ereditare da un puntatore. Uno non dovrebbe anche ereditare dai contenitori standard in quanto manca un distruttore virtuale; una possibilità è di ereditare in modo private o protected e rendere visibili tutti i simboli e le funzioni tramite typedef e using. Alla fine, dovrai riscrivere l'intero vettore e i suoi iteratori che inoltrano le chiamate all'implementazione di base.

Problemi correlati