Iterieren und Behälter von Smart-Pointer
-
20-09-2019 - |
Frage
ich einen Container von Smart-Pointer auf veränderliche Objekte haben. Ich habe zu schreiben, zwei for_each Induktionsschleifen, ein die Objekte als Nur-Lese-Daten und eine andere für veränderbare Daten für den Zugriff. Der Compiler sagt mir, dass std::vector< boost::shared_ptr<Object> >
ist nicht das gleiche wie std::vector< boost::shared_ptr<const Object> >
, beachten Sie die const
.
Hier ist mein Beispielcode:
#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;
};
Bei all den oben genannten Details, wie implementiere ich die reinen abstrakten Methoden von Record_Base
in Record_Derived
?
Ich habe versucht:
- Rückkehr
m_fields.begin()
, die
kehrt Konvertierungsfehler (nicht convertstd::vector<...> to Field_Iterator
) - Rückkehr
&m_fields[0]
, das ist gefährlich, weil sie Sachen übernehmen über die Interna vonstd::vector
.
BTW, ich bin mit std::for_each
nicht, weil ich über einen Behälter von Feldern Iterierte habe und einen Container von Untersätzen.
Lösung
Was Sie ähnelt tun sowohl die Composite- und Besucher Muster. Diese beiden Muster gut ineinander greifen, so dass es scheint, dass Sie auf dem richtigen Weg sind.
Um die zusammengesetzten Muster zu implementieren, weisen die folgenden Rollen (siehe Kompositum-Muster UML-Diagramm):
- Leaf ->
Field
- Verbund ->
Record
- Komponente -> Abstrakte Basisklasse von
Field
undRecord
(kann nicht denken Sie an einen guten Namen)
Komponenten Operationen, die auf Composite-Typen genannt werden, werden auf rekursiv auf alle Kinder weitergegeben (Blätter und anderer verschachtelter Composite-Typ).
das Besuchermuster zu implementieren, Überlastung operator()
in Ihrer Funktor Klasse für jede Komponente Subtyp (Field und Record).
Ich empfehle, dass Sie eine Kopie der erhalten Design Patterns Buch von der „Gang of Four“, die diese Konzepte besser erklärt und viel mehr Details als ich geht in nur kann.
Hier ist ein Beispielcode zu wetzen Ihren Appetit:
#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);
}
Nehmen Sie, möchten Sie vielleicht, Verfahren zur Manipulation / Zugriff auf Kinder, statt der Rückkehr einen Verweis auf die zugrunde liegenden Kinder Vektor.
Andere Tipps
würde ich vorschlagen, keine eigene Iterator zu schreiben, wenn Sie einen gemeinsamen Behältertyp verwenden. einen eigenen Iterator Schreiben macht Sinn, wenn Sie einen eigenen Container schreiben. Wenn Sie jedoch eine benutzerdefinierte schreiben planen Iterator haben einen Blick auf die Boost.Iterator Paket.
Wenn Sie zu verstecken std::vector
wollen und seine Iteratoren vom Benutzer, dann müssen Sie polymorphe Iteratoren bieten mit Ihrem polymorphen RecordBase
Behälter zu gehen. Schauen Sie sich any_iterator
von der Adobe-ASL-Bibliothek. Diese Links auch hilfreich sein kann.
Doch anstatt diese Mühe auf alle gehen, sollten Sie die Composite-und Besucherverhalten in Ihrem Design in Betracht ziehen. Sehen Sie meine andere Antwort.