2011-10-19 9 views
6

Hay tal código:Wrap vector de STL y el cambio de comportamiento de su iterador

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

Este es un contenedor de std::vector con mis propias funciones adicionales. Me gustaría utilizar iterador std::vector 's, sin embargo quiero sólo para cambiar el comportamiento de operator* de iterador:

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

¿Cómo puedo usar std::vector y su iterador con la modificación de sólo el operator*? También me gustaría envolver funciones como iterador, begin() y end(), ¿cómo ajustarlas correctamente?

EDIT:

Utilizando puntas de las respuestas en este tema, he conseguido resolver mi problema en la siguiente forma:

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

tal vez va a ser útil para alguien.

+0

Sí. Leí mal el código. No estoy seguro de cómo sucedió eso. –

Respuesta

3

El embalaje de los stdlib iterators se realiza mejor con los adaptadores de iterador. Esta tarea está lejos de ser trivial y existe la biblioteca Boost.Iterator para simplificar la tarea. Tal vez uno de los iteradores provistos ya resuelve tu problema.

Si va a escribir esto por su cuenta (I realmente no recomiendo esto), usted debe implementar su propio iterador y tiene que ser construible a partir de una vector::iterator, entonces sobrecargar todos los operadores necesarios para cumplir los requisitos del concepto que sus nuevos modelos de iterador. También herede de std::iterator para obtener los rasgos funcionando. No olvides tener la variante de const. This book tiene un capítulo dedicado a desarrollar sus propios iteradores. Obtenga también una copia del estándar (C++ 03 o C++ 11, no importa mucho aquí). Lo vas a necesitar.

+1

También necesita implementar un contenedor para 'std :: vector' si quiere usarlo de forma transparente (lo que sugiere su pregunta). –

+0

@ BjörnPollex La clase parece que solo va a necesitar un adaptador. Su clase no parece ser un modelo completo de 'Secuencia' y exponer' begin() 'y' end() 'solo debería requerir iteradores. – pmr

1

Desafortunadamente, la única forma de hacerlo es escribir un contenedor completo para std::vector y sus tipos de iterador. Esto es un montón de trabajo.

-1

Creo que la respuesta aquí es muy probable que no debería cambiar el comportamiento del operador * para un iterador. La sobrecarga del operador debe realizarse solo en casos en que sea tan extremadamente intuitivo que cualquier persona que lea el código que utiliza el operador sabrá automáticamente lo que está sucediendo. Un ejemplo de esto sería si tuvieras una clase de matriz y un operador + sobrecargado. Cuando alguien lo ve añadiendo dos objetos de matriz, puede saber fácilmente lo que está sucediendo.

Sin embargo, al desreferenciar un iterador, no hay un sentido intuitivo de cuáles serán los efectos secundarios adicionales para su clase.

+1

Oh, cambiar el comportamiento de 'operator *' puede ser extremadamente útil. Piensa 'iteradores de transformación'. – pmr

1

Uno no hereda de std::vector<T>::iterator ya que no necesita ser una clase. En algunas implementaciones esto es solo un typedef para T*, y no se puede heredar de un puntero. Uno tampoco debería heredar de contenedores estándar ya que carecen de un destructor virtual; una posibilidad es heredar de una manera private o protected y hacer visibles todos los símbolos y funciones por medio de typedef y using. Al final, tendrá que volver a escribir todo el vector y sus iteradores que reenvían llamadas a la implementación base.

Cuestiones relacionadas