質問

可変オブジェクトへのスマート ポインターのコンテナーがあります。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_BaseRecord_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">リンクます。

しかし、代わりにすべてのことトラブルに行くのは、あなたのデザインのコンポジットおよびビジターパターンを使用して検討すべきです。私の他の回答を参照してください。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top