Domanda

Ho un contenitore di puntatori intelligenti per oggetti mutabili. Devo scrivere due for_each spire, uno per accedere agli oggetti come dati di sola lettura e un altro per i dati mutabili. Il compilatore mi sta dicendo che std::vector< boost::shared_ptr<Object> > non è lo stesso di std::vector< boost::shared_ptr<const Object> >, notare il const.

Ecco il mio codice di esempio:

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

In considerazione tutti i dati riportati in alto, come faccio a implementare i metodi astratti puri di Record_Base in Record_Derived?

Ho provato:

  • m_fields.begin() ritorno, che
    restituisce errori di conversione (non può convertire std::vector<...> to Field_Iterator)
  • &m_fields[0] ritorno, che è pericoloso, perché si presuppone roba circa la struttura interna di std::vector.

A proposito, non sto usando std::for_each perché devo iterare su un contenitore di campi e di un contenitore di sub-record.

È stato utile?

Soluzione

Quello che stai facendo assomiglia sia il composito e noreferrer visitatori modelli. Questi due modelli di maglia bene insieme, così sembra siete sulla strada giusta.

Per implementare il composite, assegnare i seguenti ruoli (vedere composite diagramma UML):

  • Leaf -> Field
  • Composite -> Record
  • Componente -> Astratto classe base di Field e Record (non riesco a pensare a un buon nome)

operazioni componenti che sono chiamati tipi compositi, vengono passati in modo ricorsivo a tutti i bambini (Foglie e altri tipi di compositi nidificati).

Per implementare il modello di Visitatore, sovraccarico operator() nelle classi functor per ogni sottotipo componente (Field e Record).

Mi raccomando che si ottiene una copia del Design Patterns libro del "Banda dei Quattro", che spiega questi concetti meglio e va in modo molto più dettagliato di quanto mi sarà possibile.

Ecco alcuni esempi di codice per stuzzicare l'appetito:

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

In Record, si consiglia di fornire metodi per la manipolazione / accesso i bambini, invece di restituire un riferimento al sottostante vettore bambini.

Altri suggerimenti

Vorrei suggerire di non scrivere una propria iteratore quando si utilizza un tipo di contenitore comune. Scrivere un proprio iteratore ha senso quando si scrive un proprio contenitore. Tuttavia, quando si sta progettando di scrivere un iteratore personalizzato hanno uno sguardo al pacchetto Boost.Iterator .

Se si desidera nascondere std::vector ed i suoi iteratori da parte dell'utente, allora si avrà bisogno di fornire iteratori polimorfici di andare avanti con il vostro contenitore RecordBase polimorfico. Scopri any_iterator dalla libreria Adobe ASL. Questi link può anche essere utile.

Tuttavia, invece di andare a tutta quella fatica, è consigliabile utilizzare le composite e dei visitatori nella progettazione. Vedere la mia altra risposta.

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