스마트 포인터의 반복 및 컨테이너
-
20-09-2019 - |
문제
나는 돌연변이 가능한 물체에 대한 스마트 포인터의 컨테이너가 있습니다. 나는 둘을 써야한다 각각 루프, 하나는 객체에 읽기 전용 데이터로 액세스하고 다른 하나는 변이 가능한 데이터를위한 것입니다. 컴파일러가 나에게 말하고 있습니다 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 라이브러리에서. 이것들 연결 도움이 될 수도 있습니다.
그러나 모든 문제에 빠지지 않고 디자인에서 복합재 및 방문자 패턴을 사용하는 것을 고려해야합니다. 내 다른 대답을 참조하십시오.