Pergunta

Eu tenho um recipiente de indicadores inteligentes para objetos mutáveis. Eu tenho que escrever dois para cada Loops, um para acessar os objetos como dados somente leitura e outro para dados mutáveis. O compilador está me dizendo que std::vector< boost::shared_ptr<Object> > não é o mesmo que std::vector< boost::shared_ptr<const Object> >, Note o const.

Aqui está o meu código de exemplo:

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

Dados todos os detalhes acima, como implemento os métodos abstratos puros de Record_Base dentro Record_Derived?

Eu tentei:

  • retornando m_fields.begin(), que
    Retorna erros de conversão (não consigo converter std::vector<...> to Field_Iterator)
  • retornando &m_fields[0], o que é perigoso, porque assume coisas sobre os internos de std::vector.

Btw, eu não estou usando std::for_each Porque eu tenho que iterar sobre um recipiente de campos e um recipiente de sub-registros.

Foi útil?

Solução

O que você está fazendo se assemelha a ambos Composto e Visitante padrões. Esses dois padrões combinam bem, então parece que você está no caminho certo.

Para implementar o padrão composto, atribua as seguintes funções (consulte o diagrama UML padrão composto):

  • Folha -> Field
  • Composto -> Record
  • Componente -> Classe base abstrata de Field e Record (Não consigo pensar em um bom nome)

As operações de componentes que são chamadas em tipos compostos são transmitidas recursivamente a todas as crianças (folhas e outros tipos compostos aninhados).

Para implementar o padrão do visitante, sobrecarga operator() Nas suas classes de functor para cada subtipo de componente (campo e registro).

Eu recomendo que você obtenha uma cópia do Padrões de design Livro da "Gang of Four", que explica melhor esses conceitos e entra em muito mais detalhes do que posso.

Aqui está algum código de exemplo para aguçar seu apetite:

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

No registro, convém fornecer métodos para manipular/acessar crianças, em vez de devolver uma referência ao vetor de crianças subjacentes.

Outras dicas

Eu sugeriria não escrever um iterador próprio quando você usa um tipo de contêiner comum. Escrever um iterador próprio faz sentido quando você escreve um próprio contêiner. No entanto, quando você planeja escrever um iterador personalizado, dê uma olhada no Boost.iterator pacote.

Se você quiser se esconder std::vector e seus iteradores do usuário, então você precisará fornecer aos iteradores polimórficos para acompanhar seu polimórfico RecordBase recipiente. Verificação de saída any_iterator da biblioteca Adobe ASL. Esses links também pode ser útil.

No entanto, em vez de ir a todo esse problema, considere usar os padrões de compostos e visitantes em seu design. Veja minha outra resposta.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top