Frage

Entschuldigt, wenn dies zuvor gestellt wurde, bin ich nicht ganz sicher, ob die Terminologie oder wie die Frage zu stellen.

Ich frage mich, ob es Bibliotheken oder Best Practices sind für Objektmodelle in C ++ Implementierung. Wenn ich eine Reihe von Klassen, wo Instanzen dieser Klassen Beziehungen zueinander haben und können voneinander über verschiedene Methoden zugegriffen werden, ich will einen guten Satz von zugrunde liegenden Datenstrukturen holen diese Instanzen und deren Beziehungen untereinander zu verwalten. Dies ist leicht in Java, da es die Speicherzuweisung und die Garbage Collection für mich behandelt, aber in C ++ Ich habe das selbst zu tun.

HTML Document Object Model (DOM) ist ein Beispiel; als ein anderes (erfundenes) Beispiel: Angenommen, ich habe diese Klassen:

  • Entity
  • Person (Unterklasse von Entity)
  • Couple (Unterklasse von Entity)
  • Property
  • House (Unterklasse von Property)
  • Pet (Unterklasse von Property)
  • Car (Unterklasse von Property)

und diese Beziehungen:

  • Entity
    • hat 1 home der Klasse House
    • hat 0 oder mehr pets der Klasse Pet
    • hat 0 oder mehr cars der Klasse Car
    • hat 0 oder mehr children der Klasse Person
  • Person
    • hat 0 oder 1 spouse der Klasse Person
    • hat 0 oder 1 marriage der Klasse Couple
    • hat 0 oder 1 parents der Klasse Entity (in diesem Modell Eltern nicht existieren, wenn sie nicht mehr am Leben sind!)
  • Couple
    • hat 2 members der Klasse Person
  • Property
    • hat 1 owner der Klasse Entity

Nun, da ich gedacht habe diese Objekte und ihre Beziehungen, ich möchte, dass sie zu handhaben Datenstrukturen und Methoden und Felder starten, und hier ist, wo ich verloren gehen, da ich mit Speicherzuweisung und Lebensdauer-Management zu tun haben und all das Zeug. Sie können Probleme wie folgt ausgeführt: Ich möchte vielleicht ein Objekt in einem std::map oder std::vector setzen, aber wenn ich das tue, kann ich nicht speichern Zeiger auf diese Objekte, da sie verlegt werden, wenn die Karte oder Vektor wächst oder schrumpft.

Ein Ansatz, den ich verwenden, wenn ich viel mit COM arbeite, ist eine versteckte Sammlung zu haben, die alles enthalten ist. Jedes Objekt in der Sammlung hatte eine eindeutige ID (entweder eine Zahl oder Namen), mit der sie aus der Sammlung nachgeschlagen werden kann, und jedes Objekt hatte einen Zeiger auf die Sammlung. Auf diese Weise, wenn Sie ein Objekt, das auf ein anderes Objekt zeigen will, statt wahrsten Sinne des Wortes einen Zeiger auf ein anderes Objekt zu halten, ich die ID speichern und bis über die verborgene Sammlung aussehen kann. Ich kann einen Referenzzähler verwenden, um automatisch mit Lebensdauer Fragen zu befassen (außer für den Fall disjunkter Zyklen, manchmal ist das kein Problem).

Gibt es andere Ansätze? Oder gibt es Bibliotheken diese Art von Sachen einfacher machen in C ++?

Bearbeiten , dann haben Sie andere Fragen, wie die Beziehungen zwischen den Objekten sind wahrscheinlich in vielen Fällen wandelbar sein, und Sie müssen weiter denken darüber, wie Verweise auf Objekte gespeichert werden sollen, und was Methoden sollten für den Zugriff auf Objekte voneinander bereitgestellt werden. Zum Beispiel, wenn ich einen Punkt zu einem Person X haben, und ich möchte das Konzept der „finden X Kind namens George“ repräsentieren, dann muss ich den Namen speichern „George“ und nicht als ein Kind Nummer: die Kinder können gespeichert werden in einem Vektor, und ich kann in der Lage seinrufen X.getChildCount () und X.getChild (0), aber „George“ sein Kind Nummer 0 kann nicht immer da andere Kinder vor „George“ in dem Kind Vektor eingeführt werden können. Oder X kann zwei oder drei oder vier andere Kinder auch den Namen „George“. Oder „George“ kann seinen Namen ändern zu „Anthony“ oder „Georgina“. In all diesen Fällen ist es wahrscheinlich besser, eine Art einzigartiger unveränderlicher ID zu verwenden.

Bearbeiten 2: ich mit der Wahl der Methoden umgehen können und Eigenschaftsnamen, ich kann behandeln (und ich werde meine Frage etwas sobald ich diese begradigt aufzuräumen), ob die Verwendung eine Karte oder eine Liste oder ein Vektor. Das ist ziemlich einfach. Die Probleme, ich versuche, mit speziell zu behandeln sind:

  • , wie einen Objektspeicher haben, ein Verweis auf ein anderes Objekt, wenn diese Objekte können einen Teil von Datenstrukturen sein, die neu zugewiesen werden
  • , wie mit dem Objekt Lebensdauer-Management beschäftigen, wenn es gegenseitige Beziehungen zwischen Objekten
War es hilfreich?

Lösung

Sie schrieb über Objekte aus der Objektmodell innerhalb std :: vector usw. und Probleme mit der Verwendung von Zeigern, um sie zu speichern. Das erinnert mich, dass es gut ist Ihre C ++ Klassen in zwei Kategorien zu unterteilen (Ich bin nicht sicher Terminologie hier):

  1. Entitätsklassen , die Objekte darstellen, die Teil des Objektmodells sind. Sie sind in der Regel polymorph oder möglicherweise in der Zukunft sein wird. Sie werden auf Heap erstellt und werden immer durch Zeiger oder intelligenten Zeiger verwiesen wird. Sie sie nie direkt erstellen auf Stapel, als Klasse / Struktur Mitglieder noch setzen sie direkt in Container wie std :: Vektoren. Sie haben nicht Copykonstruktor noch Betreiber = (Sie eine neue Kopie mit einiger Clone-Methode machen können). Sie können sie (ihre Staaten) vergleichen, wenn es für Sie von Bedeutung ist, aber sie sind nicht austauschbar, weil sie Identität haben. Jeweils zwei Objekte unterscheiden.

  2. Wertklassen , die primitiven benutzerdefinierte Typen implementieren (wie Strings, komplexe Zahlen, große Zahlen, intelligente Zeiger, Griff-Wrapper, etc). Sie werden direkt auf dem Stack oder als Klasse / Struktur Mitglieder erstellt. Sie sind kopierbar mit Copykonstruktor und Operator =. Sie sind nicht polymorph (polymorhism und Operator = nicht funktionieren gut zusammen). Sie setzen oft ihre Kopien innerhalb stl Containern. Sie speichern selten Hinweise auf sie in unabhängigen Standorten. Sie sind untereinander austauschbar. Wenn zwei Instanzen den gleichen Wert haben, können Sie sich als gleich behandeln. (Die Variablen, die ihnen sind verschiedene Dinge obwohl enthalten.)

Es gibt viele sehr gute Gründe, über Regeln zu brechen. Aber ich beobachtete, dass sie von Anfang an führt zu Programmen zu ignorieren, die nicht lesbar sind, unzuverlässig (vor allem, wenn es um die Speicherverwaltung kommt) und schwer zu pflegen.


Nun zurück zu Ihrer Frage.

Wenn Sie ein Datenmodell mit komplexen Beziehungen und einfache Weise speichern wollen Abfragen zu tun wie „X Kind namens George finden“, warum nicht einige In-Memory-relationale Datenbank?

Beachten Sie, dass, wenn Sie effizient a) komplexere bidirektionale Beziehungen gehen zu implementieren und b) Abfragen basierend auf verschiedenen Objekteigenschaften, dann werden Sie wahrscheinlich indexierten Datenstrukturen erstellen müssen, die sehr ähnlich zu dem, was relationalen Datenbank innerhalb der Fall ist. Sind Ihre Implementierungen (wie es viele sein werden, in Einzelprojekt) wirklich effektiver und robust sein würde?

Das Gleiche gilt für „Sammlungen von allem“ und Objekt-IDs. Sie müssen Beziehungen zwischen Objekten verfolgen ohnehin IDs ohne Objekte zu vermeiden. Wie unterscheidet es sich von Zeigern? Andere dann sinnvoll immer Fehler statt der ganzen Speicher verrückt zu werden, das heißt, -)


Einige Ideen für die Speicherverwaltung:

  • Starke Eigentümer:., Wenn Sie, dass einige Unternehmen nur erklären können, solange sein Besitzer wohnt und es gibt keine Möglichkeit, unabhängig existierende Zeiger auf sie, können Sie einfach es ist destructor in Eigentümer löschen (oder mit scoped_ptr)

  • Jemand bereits vorgeschlagen smart_ptr. Sie sind groß und können mit stl Behälter verwendet werden. Sie sind Referenz couter basiert aber so nicht schaffen Zyklen :-(. Ich bin nicht bekannt, dass weit verbreitet c ++ automatische Hinweise, die Zyklen verarbeiten kann.

  • Vielleicht gibt es einige Top-Level-Objekt, das alle anderen Objekte besitzt. Z.B. Sie können oft sagen, dass alle Stücke zu einem Dokument oder einen Algorithmus oder eine Transaktion gehören. Sie können in Zusammenhang mit dem Top-Level-Objekt erstellt werden und dann automatisch gelöscht, wenn ihr Top-Level-Objekt gelöscht wird (wenn Sie Dokument aus dem Speicher oder das Ende der Ausführung des Algorithmus entfernen). Natürlich kann man nicht Stücke zwischen Objekten oberster Ebene teilen.

Andere Tipps

Es gibt etwa eine Million (bei einer konservativen Schätzung) zu dieser annähert. Sie fragen wirklich „wie gestalte ich Software in C ++“. Und die Antwort ist, fürchte ich, „was ist Ihre Software zu tun?“ -. Einfach zu wissen, dass Sie mit Personen umgehen wollen und Häuser sind nicht genug

Ist das nicht der ganze Sinn der OOP? Das, was Sie fordern ist eine Implementierung Detail, dass Sie hinter der öffentlichen Schnittstelle dieser Klassen verstecken, und müssen daher nicht darum kümmern, weil Sie es ohne Änderung der Schnittstelle ändern? Also los, versuchen Sie es die Art und Weise, die Sie vorschlagen. Dann, wenn es eine Leistung, Speicher oder anderes Problem ist, können Sie die Implementierung beheben, ohne, ohne den Rest des Codes zu brechen.

Es sieht für mich, dass Ihre Daten in einer Datenbank zu speichern und verwenden irgendeine Art von objekt-relationalen Mapping, könnte eine weitere Option zu betrachten.

könnten Sie verwenden boost :: shared_ptr die Speicherprobleme zu adressieren. Sie können dann den Shared_ptr frei um kopieren, bringen Sie es von Funktionen, sie als lokalen Variable verwenden, etc.

könnte ein Person dann ein std::map< string, boost::shared_ptr<Person> > haben, so X.getChild("George") würde einfach das Kind in der Karte nachschauen und den Zeiger zurück. Ich denke, dass Sie das Konzept bekommen, so dass ich den Rest als eine Übung, dich verlassen;)

Jason, meine Lieblingsquelle auf die ist das C ++ FAQ Buch . Das Problem ist, Sie fragen effektiv „wie kann ich C ++ verwenden, für die objektorientierte Programmierung?“

Das Beste, was ich in einem SO Antwort sagen kann, ist dies:

all diese Dinge sein werden Klassen in C ++, und die Beziehungen usw. werden viel wie Müll gesammelt Sprachen sehen Sie es gewohnt sind: Wenn Sie eine Beziehung zwischen einer Person und seinem Kind den Namen „George“ benötigen, können Sie wählen eine Datenstruktur, die Personen oder Childs indiziert nach Namen speichern können.

Speicherverwaltung ist eigentlich einfacher als in geraden C, wenn Sie einige Regeln beachten: Stellen Sie sicher, dass die Objekte alle, die sie Destruktoren haben müssen, stellen Sie sicher, dass die Destruktoren das Objekt aufzuräumen alles besitzt, und stellen Sie sicher, dass Sie immer diese setzen Objekte dynamisch in einem Kontext aufgebaut, wo sie außerhalb des Bereichs gehen, wenn sie nicht mehr sind erforderlich. Diese werden nicht alle Fälle abdecken, aber sie werden Sie von wahrscheinlich 80 Prozent der Speicherzuweisung Fehler speichern.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top