Ich habe einen Datei-Parser für ein Spiel geschrieben, damit ich verschiedene Aspekte des Spiels (Dinge wie Charakter / Bühne / Kollisionsdaten) leicht ändern kann. Zum Beispiel könnte ich eine Zeichenklasse wie folgt haben:
%Vor%Ich habe meinen Parser eingerichtet, um die Datenstruktur mit einer C ++ ähnlichen Syntax aus einer Datei einzulesen.
%Vor% Dadurch werden zwei Datenstrukturen erstellt und in eine Karte <std::string, Character*>
eingefügt, wobei die Schlüsselzeichenfolge den Namen hat, den ich ihr gegeben habe (in diesem Fall Sidekick und AwesomeDude). Wenn mein Parser einen Zeiger auf eine Klasse sieht, wie den Teammate-Zeiger, ist es schlau genug, in der Map nachzuschlagen, um den Zeiger auf diese Datenstruktur zu holen. Das Problem ist, dass ich Teamkamerad von Sidekick nicht als AwesomeDude deklarieren kann, weil es noch nicht in der Charakterkarte platziert wurde.
Ich versuche, den besten Weg zu finden, dieses Problem zu lösen, damit meine Datenstrukturen auf Objekte verweisen können, die der Karte noch nicht hinzugefügt wurden. Die zwei einfachsten Lösungen, die ich mir vorstellen kann, sind (a) die Möglichkeit, Datenstrukturen zu deklarieren oder (b) den Parser zweimal durch die Datei zu lesen, einmal um die Karte mit Zeigern zu leeren Datenstrukturen zu füllen und ein zweites Mal gehe durch und fülle sie aus.
Das Problem mit (a) ist, dass ich auch entscheiden kann, welcher Konstruktor eine Klasse aufrufen soll, und wenn ich etwas deklariere, müsste der Konstruktor vom Rest der Daten getrennt sein, was verwirrend sein könnte . Das Problem mit (b) ist, dass ich Sidekick und AwesomeDude in ihren eigenen Dateien deklarieren möchte. Ich müsste meinen Parser in die Lage versetzen, eine Liste von Dateien zu lesen anstatt nur einzeln zu lesen (das ist nicht so schlimm, denke ich, obwohl ich manchmal eine Liste von Dateien zum Lesen von a Datei). (b) hat auch den Nachteil, dass Datenstrukturen, die später im Konstruktor selbst deklariert werden, nicht verwendet werden können, aber ich denke nicht, dass das eine große Sache ist.
Welcher Weg klingt nach einem besseren Ansatz? Gibt es eine dritte Option, an die ich nicht gedacht habe? Es scheint so, als müsste es eine clevere Lösung mit Pointer-Referenzen oder Binding oder etwas geben ...: - / Ich nehme an, das ist etwas subjektiv, basierend auf den Features, die ich mir selbst geben möchte, aber jede Eingabe ist willkommen.
Wenn Sie die Referenz das erste Mal vorfinden, speichern Sie sie einfach als Referenz. Dann können Sie das Zeichen oder die Referenz oder was auch immer auf eine Liste von "Referenzen, die später gelöst werden müssen" setzen.
Wenn die Datei fertig ist, durchlaufen Sie diejenigen, die Referenzen haben und lösen Sie sie.
Nun, Sie haben nach einer dritten Option gefragt. Sie müssen nicht XML verwenden, aber wenn Sie der folgenden Struktur folgen, wäre es sehr einfach, einen SAX-Parser zu verwenden, um Ihre Datenstruktur aufzubauen.
Jedenfalls verweist jeder Charakter, anstatt auf einen Teamkollegen zu verweisen, auf ein Team (in diesem Fall ein blaues Team). Dies wird das zirkuläre Referenzproblem entkoppeln. Stellen Sie nur sicher, dass Sie die Teams vor den Charakteren auflisten.
%Vor%Ich persönlich würde mit b) gehen. Teilen Sie Ihren Code in Parser- und Validator-Klassen, die beide dieselbe Datenstruktur verwenden. Der Parser liest und analysiert eine Datei, füllt die Datenstruktur und speichert alle Objektreferenzen als ihre Textnamen, so dass der echte Zeiger in Ihrer Struktur vorerst null bleibt.
Wenn Sie mit dem Laden der Dateien fertig sind, verwenden Sie die Validator-Klasse, um Referenzen zu validieren und aufzulösen, indem Sie die "echten" Zeiger ausfüllen. Sie sollten überlegen, wie Sie Ihre Daten strukturieren können, um diese Lookups schön und schnell zu machen.
Speichern Sie einen Proxy für das Zeichen, anstatt das Zeichenobjekt in der Karte zu speichern. Der Proxy enthält dann einen Zeiger auf das tatsächliche Zeichenobjekt, wenn das Objekt geladen wird. Der Typ von Character :: Teammate wird in diesen Proxy-Typ geändert. Wenn Sie eine Referenz einlesen, die nicht bereits in Ihrer Map enthalten ist, erstellen Sie einen Proxy und verwenden den Proxy. Wenn Sie ein Zeichen laden, für das Sie bereits einen leeren Proxy in der Karte haben, füllen Sie es mit Ihrem neu geladenen Zeichen. Vielleicht möchten Sie auch einen Zähler hinzufügen, um zu verfolgen, wie viele leere Proxy Sie in der Karte haben, so dass Sie wissen, wenn alle referenzierten Zeichen geladen wurden.
Eine weitere Ebene der Indirektion ... es macht die Programmierung immer einfacher und langsamer.
Tags und Links c++ parsing fileparsing