2017-09-12 4 views
0

Ich entwerfe eine Schnittstelle (eine abstrakte Klasse) in C++, die Art von Baumstruktur implementiert: jede Instanz hat null, eine oder mehrere Kinder. Die Kinder sind auch Instanzen der Schnittstelle.Zugriff auf Sammlung von abstrakten Klassen

Ich habe in der Regel ziemlich viel über eine Schnittstelle nachgedacht, um bestimmte Implementierungen nicht auszuschließen. Zum Beispiel sollten Methoden keine Referenzen zurückgeben, da dies die Implementierung zwingt, den Wert irgendwo zu speichern. Dies würde Implementierungen ausschließen, die den Wert bei jedem Aufruf neu berechnen. oder Wrapper, die den zurückgegebenen Wert in irgendeiner Weise transformieren.

Mit dieser Schnittstelle bin ich jedoch unsicher über die beste Möglichkeit, den Kindern einer Instanz den Zugriff zu ermöglichen. Bisher habe ich mit zwei Optionen kommen:

class Interface 
{ 
public: 

    virtual ~Interface() = default; 

    // IDEA 1: return a collection of references. 
    virtual auto getChildren() const -> std::vector<std::reference_wrapper<Interface>> = 0; 

    // IDEA 2: accept a visitor. 
    virtual void visitChildren(const std::function<void(Interface&)> &visitor) const = 0; 

}; 

Meine Frage:, was das Beste ist * Art und Weise Zugang zu einer Sammlung von abstrakten Klassen zur Verfügung zu stellen. Andere Ideen und Ansätze werden sehr geschätzt (z. B. ein Iterator-basierter Ansatz, wenn überhaupt möglich).

* Einige oder alle der folgenden Eigenschaften: Die meisten idiomatische, flexibelste, skalierbarste, die meisten wartbar, intuitivste, semantisch stärkste, ...

+3

Haben Sie schon von Iteratoren gehört? Das ist irgendwie das dominierende Idiom in C++. Schauen Sie sich einfach die Standardbibliothek an. – StoryTeller

+0

@StoryTeller Könnten Sie mir ein Beispiel dafür geben, wie ich Iteratoren verwenden würde (wenn man bedenkt, dass die Funktionen 'begin' und' end' auch rein virtuell sein müssen)? Oder denke ich über den Iterator-Ansatz falsch nach? –

+0

Think co-Variante Rückgabetypen (irgendwie). Sie geben ein Handle für einen abstrakten Iterator zurück. 'begin' und' end' müssten natürlich virtuell sein. – StoryTeller

Antwort

1

Platzierung der Diskussion über Ihr Design beiseite zu Java-like sein . Wenn Sie idiomatische C sein wollen ++, gehen Sie für Iteratoren:

class Interface { 
    class iterator_impl { 
    virtual ~iterator_impl() = default; 
    // Fill the rest 
    }; 
public: 
    class iterator { 
    std::unique_ptr<iterator_impl> _impl; 
    iterator(std::unique_ptr<iterator_impl> impl) : _impl(std::move(impl)) {} 
    public: 
    Iterface& operator*() { 
     //forward to _impl 
    } 
    }; 

    virtual iterator begin() = 0; 
    virtual iterator end() = 0; 
}; 

Nach der vollständigen Iterator-Protokoll liefert, kann ein Interface& in idiomatischen C++ Code verwendet werden:

void foo(Interface& interface) { 
    for(auto& i : interface) { 
    //Do stuff 
    } 
} 
Verwandte Themen