Question

J'ai un conteneur de pointeurs intelligents aux objets mutables. Je dois écrire deux for_each boucles, l'une pour accéder aux objets de données en lecture seule et une autre pour les données mutables. Le compilateur me dit que std::vector< boost::shared_ptr<Object> > n'est pas la même chose que std::vector< boost::shared_ptr<const Object> >, notez le const.

Voici mon exemple de code:

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

Compte tenu de tous les détails ci-dessus, comment puis-je mettre en œuvre les méthodes abstraites pures de Record_Base dans Record_Derived?

J'ai essayé:

  • m_fields.begin() retour, qui
    renvoie des erreurs de conversion (non convertir std::vector<...> to Field_Iterator)
  • &m_fields[0] retour, ce qui est dangereux, car elle suppose des choses sur les entrailles de std::vector.

BTW, je ne suis pas en utilisant std::for_each parce que je dois itérer sur un conteneur de champs et un conteneur de sous-dossiers.

Était-ce utile?

La solution

Qu'est-ce que vous faites ressemble à la fois Composite et noreferrer modèles des visiteurs. Ces deux modèles de maillage bien ensemble, il semble que vous êtes sur la bonne voie.

Pour mettre en œuvre le modèle composite, attribuer les rôles suivants (voir diagramme UML pattern Composite):

  • Feuille -> Field
  • Composite -> Record
  • Component -> Classe de base abstraite de Field et Record (ne peut pas penser à un nom)

Opérations de composants qui sont appelés types composites, sont transmis de façon récursive à tous les enfants (feuilles et autres types imbriqués composites).

Pour mettre en œuvre le modèle des visiteurs, operator() de surcharge dans vos classes de foncteurs pour chaque sous-type de composants (champ et enregistrement).

Je recommande que vous obtenez une copie de la Design Patterns livre du « Gang of Four », ce qui explique ces concepts mieux et va dans beaucoup plus de détails que je le peux.

Voici quelques exemples de code pour aiguiser votre appétit:

#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 enregistrement, vous pouvez fournir des méthodes de manipulation / l'accès des enfants, au lieu de retourner une référence au vecteur des enfants sous-jacent.

Autres conseils

Je suggère de ne pas écrire un propre iterator lorsque vous utilisez un type de conteneur commun. Rédaction d'un propre iterator est logique lorsque vous écrivez un récipient propre. Toutefois, lorsque vous envisagez d'écrire un itérateur personnalisé jeter un oeil à la page package Boost.Iterator .

Si vous voulez cacher std::vector et ses itérateurs de l'utilisateur, vous devrez fournir itérateurs polymorphes pour aller avec votre conteneur RecordBase polymorphes. Consultez any_iterator de la bibliothèque ASL Adobe. Ces liens peut également être utile.

Cependant, au lieu d'aller à tout ce mal, vous devriez envisager d'utiliser les modèles composites et des visiteurs dans votre conception. Voir mon autre réponse.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top