Pregunta

Tengo un contenedor de punteros inteligentes a los objetos mutables. Tengo que escribir dos for_each bucles, uno para acceder a los objetos como datos de sólo lectura y otra para los datos mutables. El compilador me dice que std::vector< boost::shared_ptr<Object> > no es lo mismo que std::vector< boost::shared_ptr<const Object> >, tenga en cuenta el const.

Aquí está mi código de ejemplo:

#include <vector>
#include "boost/shared_ptr.hpp"
#include <iterator>

class Field_Interface
{ ; };
typedef boost::shared_ptr<Field_Interface> Ptr_Field_Interface;
typedef boost::shared_ptr<const Field_Interface> Ptr_Const_Field_Interface;

struct Field_Iterator
  : std::input_iterator<std::forward_iterator_tag, Ptr_Field_Interface>
{
  // forward iterator methods & operators...
};

struct Const_Field_Iterator
  : std::input_iterator<std::forward_iterator_tag, Ptr_Const_Field_Interface>
{
  // forward iterator methods & operators...
};

struct Field_Functor
{
  virtual void operator()(const Ptr_Field_Interface&) = 0;
  virtual void operator()(const Ptr_Const_Field_Interface&) = 0;
};

class Record;
typedef boost::shared_ptr<Record> Ptr_Record;
typedef boost::shared_ptr<const Record> Ptr_Const_Record;

class Record_Base
{
  protected:
    virtual Field_Iterator beginning_field(void) = 0;
    virtual Field_Iterator ending_field(void) = 0;
    virtual Const_Field_Iterator const_beginning_field(void) = 0;
    virtual Const_Field_Iterator const_ending_field(void) = 0;

    void for_each(Field_Functor * p_functor)
    {
       Field_Iterator iter_begin(beginning_field());
       Field_Iterator iter_end(ending_field());
       for (; iter_begin != iter_end; ++ iter_begin)
       {
         (*p_functor)(*iter_begin);
       }
     }
};

class Record_Derived
{
public:
   typedef std::vector<Ptr_Field_Interface> Field_Container;
   typedef std::vector<Ptr_Record>          Record_Container;
private:
   Field_Container m_fields;
   Record_Container m_subrecords;
};

Teniendo en cuenta todos los datos anteriores, ¿Cómo implementar los métodos abstractos puros de Record_Base en Record_Derived?

He intentado:

  • m_fields.begin() regresar, que
    devuelve errores de conversión (no puede convertir std::vector<...> to Field_Iterator)
  • &m_fields[0] regresar, que es peligrosa, porque asume cosas sobre el funcionamiento interno de std::vector.

Por cierto, no estoy usando std::for_each porque tengo que repetir un contenedor de campos y un recipiente de sub-registros.

¿Fue útil?

Solución

Lo que está haciendo se parece tanto a la compuesto y noreferrer visitantes patrones. Esos dos patrones encajan bien entre sí, por lo que parece que está en el camino correcto.

Para implementar el patrón compuesto, asignan las siguientes funciones (se refieren a patrón Composite diagrama UML):

  • Hoja -> Field
  • Compuesto -> Record
  • Componentes -> clase base abstracta de Field y Record (no puede pensar en un buen nombre)

Las operaciones de componentes que se llaman en los tipos de compuesto, se transmiten de forma recursiva a todos los niños (hojas y otros tipos compuestas anidadas).

Para implementar el patrón del visitante, operator() sobrecarga en sus clases functor para cada subtipo de componentes (Field y Grabar).

Le recomiendo que se obtiene una copia de la Patrones de diseño libro de la "banda de los cuatro", lo que explica mejor estos conceptos y entra en mucho más detalle de lo que me sea posible.

A continuación, algunos ejemplos de código para abrir el apetito:

#include <iostream>
#include <vector>
#include "boost/shared_ptr.hpp"
#include "boost/foreach.hpp"

class Field;
class Record;

struct Visitor
{
    virtual void operator()(Field& field) = 0;
    virtual void operator()(Record& field) = 0;
};

class Component
{
public:
    virtual bool isLeaf() const {return true;}
    virtual void accept(Visitor& visitor) = 0;
};
typedef boost::shared_ptr<Component> ComponentPtr;

class Field : public Component
{
public:
    explicit Field(int value) : value_(value) {}
    void accept(Visitor& visitor) {visitor(*this);}
    int value() const {return value_;}

private:
    int value_;
};

class Record : public Component
{
public:
    typedef std::vector<ComponentPtr> Children;
    Record(int id) : id_(id) {}
    int id() const {return id_;}
    Children& children() {return children_;}
    const Children& children() const {return children_;}
    bool isLeaf() const {return false;}
    void accept(Visitor& visitor)
    {
        visitor(*this);
        BOOST_FOREACH(ComponentPtr& child, children_)
        {
            child->accept(visitor);
        }
    }

private:
    int id_;
    Children children_;
};
typedef boost::shared_ptr<Record> RecordPtr;

struct OStreamVisitor : public Visitor
{
    OStreamVisitor(std::ostream& out) : out_(out) {}
    void operator()(Field& field) {out_ << "field(" << field.value() << ") ";}
    void operator()(Record& rec) {out_ << "rec(" << rec.id() << ") ";}
    std::ostream& out_;
};

int main()
{
    RecordPtr rec(new Record(2));
        rec->children().push_back(ComponentPtr(new Field(201)));
        rec->children().push_back(ComponentPtr(new Field(202)));
    RecordPtr root(new Record(1));
        root->children().push_back(ComponentPtr(new Field(101)));
        root->children().push_back(rec);

    OStreamVisitor visitor(std::cout);
    root->accept(visitor);
}

En Record, es posible que desee proporcionar métodos para la manipulación / el acceso a los niños, en lugar de devolver una referencia al vector de los niños subyacente.

Otros consejos

Yo sugeriría no escribir un iterador propia cuando se utiliza un tipo de contenedor común. Escribir un propio iterador tiene sentido cuando se escribe un contenedor propia. Sin embargo, cuando usted está planeando escribir un iterador costumbre echar un vistazo a la paquete Boost.Iterator .

Si desea ocultar std::vector y sus iteradores de usuario, entonces usted tendrá que proporcionar iteradores polimórficos para ir junto con su contenedor RecordBase polimórfica. Echa un vistazo a any_iterator de la biblioteca de Adobe ASL. Estos enlaces también puede ser útil.

Sin embargo, en vez de ir a todos esos problemas, se debe considerar el uso de los patrones de composición y de los visitantes en su diseño. Ver mi otra respuesta.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top