スマート ポインターの反復とコンテナー
-
20-09-2019 - |
質問
可変オブジェクトへのスマート ポインターのコンテナーがあります。2つ書かないといけない それぞれごと 1 つは読み取り専用データとしてオブジェクトにアクセスするためのループ、もう 1 つは可変データとしてオブジェクトにアクセスするためのループです。コンパイラはそれを教えてくれます 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
.
ところで、私は使っていません std::for_each
フィールドのコンテナを反復処理する必要があるため、 そして サブレコードのコンテナ。
解決
あなたがやっていることは両方に似ています 複合 そして ビジター パターン。これら 2 つのパターンはうまく噛み合っているため、正しい方向に進んでいるように見えます。
複合パターンを実装するには、次の役割を割り当てます (「複合パターンの UML 図」を参照)。
- 葉 ->
Field
- 複合 ->
Record
- コンポーネント -> の抽象基本クラス
Field
そしてRecord
(いい名前が思いつきません)
Composite 型で呼び出されるコンポーネント操作は、すべての子 (Leave および他の入れ子になった Composite 型) に再帰的に渡されます。
Visitor パターンを実装するには、オーバーロードします。 operator()
各コンポーネントのサブタイプ (フィールドとレコード) のファンクター クラスで。
のコピーを入手することをお勧めします デザインパターン この本は、「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);
}
Record では、基になる子ベクトルへの参照を返す代わりに、子を操作/アクセスするためのメソッドを提供することができます。
他のヒント
一般的なコンテナ型を使用する場合は、独自のイテレータを作成しないことをお勧めします。独自のコンテナを作成する場合、独自のイテレータを作成することは理にかなっています。ただし、カスタムイテレータを作成する予定がある場合は、次の内容を確認してください。 Boost.Iterator パッケージ。
std::vector
、そのイテレータを非表示にしたい場合は、、あなたはあなたの多型RecordBase
コンテナと一緒に行くための多型イテレータを提供する必要があります。アドビASLライブラリから any_iterator
にチェックしてください。 これらの<のhref = "のhttp:// WWW。また、役に立つかもしれのcodeproject.com/KB/stl/polycontainer.aspx」のrel = "nofollowをnoreferrer">リンクます。
しかし、代わりにすべてのことトラブルに行くのは、あなたのデザインのコンポジットおよびビジターパターンを使用して検討すべきです。私の他の回答を参照してください。