문제

나는 돌연변이 가능한 물체에 대한 스마트 포인터의 컨테이너가 있습니다. 나는 둘을 써야한다 각각 루프, 하나는 객체에 읽기 전용 데이터로 액세스하고 다른 하나는 변이 가능한 데이터를위한 것입니다. 컴파일러가 나에게 말하고 있습니다 std::vector< boost::shared_ptr<Object> > 동일하지 않습니다 std::vector< boost::shared_ptr<const Object> >, 참고 const.

내 예제 코드는 다음과 같습니다.

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

위의 모든 세부 사항이 주어지면 순수한 추상 방법을 어떻게 구현합니까? Record_Base 안에 Record_Derived?

난 노력 했어:

  • 반환 m_fields.begin(), 어느
    변환 오류를 반환합니다 (변환 할 수 없습니다 std::vector<...> to Field_Iterator)
  • 반환 &m_fields[0], 내부에 대한 물건을 가정하기 때문에 위험합니다. std::vector.

BTW, 나는 사용하지 않습니다 std::for_each 필드 컨테이너를 반복해야하기 때문에 그리고 하위 기록의 컨테이너.

도움이 되었습니까?

해결책

당신이하는 일은 두 가지와 비슷합니다 합성물 그리고 방문객 패턴. 이 두 패턴은 함께 잘 맞아서 올바른 길을 가고있는 것 같습니다.

복합 패턴을 구현하려면 다음 역할을 할당합니다 (복합 패턴 UML 다이어그램 참조).

  • 잎 -> Field
  • 복합 -> Record
  • 구성 요소 -> 추상 기본 클래스 Field 그리고 Record (좋은 이름을 생각할 수 없음)

복합 유형으로 호출되는 구성 요소 작업은 모든 어린이 (잎 및 기타 중첩 복합 유형)에게 재귀 적으로 전달됩니다.

방문자 패턴을 구현하려면 오버로드 operator() 각 구성 요소 하위 유형에 대한 FUNCTOR 클래스 (필드 및 레코드)에서.

나는 당신이 사본을 얻는 것이 좋습니다 디자인 패턴 "Gang of Four"의 예약은 이러한 개념을 더 잘 설명하고 가능한 한 훨씬 더 자세하게 설명합니다.

식욕을 자극하는 샘플 코드는 다음과 같습니다.

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

기록상, 당신은 기본 어린이 벡터에 대한 참조를 반환하는 대신 어린이 조작/액세스 방법을 제공 할 수 있습니다.

다른 팁

공통 컨테이너 유형을 사용할 때 자체 반복자를 쓰지 말 것을 권장합니다. 자체 반복자를 작성하면 자체 컨테이너를 작성할 때 의미가 있습니다. 그러나 사용자 정의 반복기를 작성할 때 boost.iterator 패키지.

숨기고 싶다면 std::vector 그리고 사용자의 반복자는 다형성 반복자를 제공해야합니다. RecordBase 컨테이너. 체크 아웃 any_iterator Adobe ASL 라이브러리에서. 이것들 연결 도움이 될 수도 있습니다.

그러나 모든 문제에 빠지지 않고 디자인에서 복합재 및 방문자 패턴을 사용하는 것을 고려해야합니다. 내 다른 대답을 참조하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top