Zugriff auf Liste
-
Ich hab mir eben meine eigene kleine, doppelt-verkettete Liste mit C++ gebastelt. Alles funktioniert soweit wie gewünscht. Die Liste hat jeweils einen Zeiger auf das erste, letzte und aktuelle Element. Und genau da liegt das Problem.
Ich will nun von mehreren anderen Klassen aus Zugriff auf ein und dieselbe Liste haben. Die Anzahl der Klassen, die dabei Zugriff auf die Liste haben, soll quasi unbeschränkt sein.
In jede Klasse einen eigenen Zeiger auf das jeweils eigene aktuelle Element einzubauen, würde nicht Sinn der Sache sein, da die Liste dafür verantwortlich sein soll, ob Elemente verändert, gelöscht und eingesehen werden können. Dennoch sollen die Klassen, die letztendlich Zugriff auf die Liste haben, mit den Befehlen gotoNextObj() bzw. gotoLastObj() etc. das jeweils nächste / vorherige Element relativ zu dem Element, was sie vorher hatten, bekommen.
Später soll diese Liste nämlich von einer Klasse ständig durchlaufen werden, während eine zweite Klasse ("Userinterface") in der Liste beliebig hin und her stöbert. Ich hoffe mich versteht jemandIch hab mir schon einige Lösungsansätze überlegt, komme allerdings nicht wirklich weiter.
Mein Quellcode mit der einfachen Liste://-------KLASSE: OBJECT //--------------------- class Object { public: //>>>>>KONSTRUKTOR Object() { pObjNext = NULL; pObjPrev = NULL; ObjName = "-"; } //>>>>>OBJECT *OBJNEXT(INT TODO, OBJECT *POBJNEWNEXT = NULL) Object *ObjNext(int toDo = 0, Object *pObjNewNext = NULL) // setzt den Nachfolger fest, { // oder gibt den aktuellen Nachfolger zurück if (this != NULL) { if (toDo) pObjNext = pObjNewNext; return pObjNext; } return NULL; } //>>>>>OBJECT *OBJPREV(INT TODO, OBJECT *POBJNEWPREV = NULL) Object *ObjPrev(int toDo = 0, Object *pObjNewPrev = NULL) // setzt den Vorgänger fest, { // oder gibt den aktuellen Vorgänger zurück if (this != NULL) { if (toDo) pObjPrev = pObjNewPrev; return pObjPrev; } return NULL; } //>>>>>ANSISTRING OBJNAMECHG(ANSISTRING OBJNEWNAME = NULL) AnsiString ObjNameChg(AnsiString ObjNewName = NULL) // setzt den Namen des Objektes fest, { // oder gibt den Namen des Objektes zurück if (this != NULL) { if (ObjNewName != NULL) ObjName = ObjNewName; return ObjName; } return "-"; } protected: Object *pObjNext; Object *pObjPrev; AnsiString ObjName; }; //-------KLASSE: OBJECTQUEUE //-------------------------- class ObjectQueue { public: //>>>>>KONSTRUKTOR ObjectQueue() { pObjFirst = NULL; pObjFinal = NULL; pObjCurrent = NULL; ObjCount = 0; } //>>>>>VOID ADDOBJ(OBJECT *POBJNEW) void addObj(Object *pObjNew) // fügt der Liste neue Elemente hinzu { if (pObjFinal) { pObjFinal->ObjNext(1, pObjNew); pObjNew->ObjPrev(1, pObjFinal); } else { pObjFirst = pObjNew; pObjCurrent = pObjNew; } ObjCount += 1; pObjFinal = pObjNew; Form1->Info->Text = "OBJECT ADDED"; } //>>>>>VOID DESTROYOBJ() void destroyObj() // löscht das aktuelle Element, falls vorhanden { if (pObjCurrent) { Object *pObjBackup; pObjCurrent->ObjPrev()->ObjNext(1, pObjCurrent->ObjNext()); pObjCurrent->ObjNext()->ObjPrev(1, pObjCurrent->ObjPrev()); pObjBackup = pObjCurrent; if (pObjFirst == pObjCurrent) pObjFirst = pObjFirst->ObjNext(); if (pObjFinal == pObjCurrent) { pObjFinal = pObjFinal->ObjPrev(); pObjCurrent = pObjCurrent->ObjPrev(); } else pObjCurrent = pObjCurrent->ObjNext(); delete pObjBackup; ObjCount -= 1; Form1->Info->Text = "OBJECT DESTROYED"; } else Form1->Info->Text = "THERE IS NO CURRENT OBJECT"; } //>>>>>VOID GOTONEXTOBJ() void gotoNextObj() // setzt das aktuelle Element ein Element weiter { if (pObjCurrent->ObjNext()) { pObjCurrent = pObjCurrent->ObjNext(); Form1->Info->Text = "GOTO NEXT OBJECT"; } else Form1->Info->Text = "THERE IS NO NEXT OBJECT"; } //>>>>>VOID GOTOPREVOBJ() void gotoPrevObj() // setzt das aktuelle Element ein Element zurück { if (pObjCurrent->ObjPrev()) { pObjCurrent = pObjCurrent->ObjPrev(); Form1->Info->Text = "GOTO PREVIOUS OBJECT"; } else Form1->Info->Text = "THERE IS NO PREVIOUS OBJECT"; } //>>>>>ANSISTRING SHOWOBJNAME(INT WICHOBJ = 1) AnsiString showObjName(int wichObj = 1) // gibt den Namen des gewünschten Objektes zurück, { // oder "-" if (pObjCurrent) { if (wichObj == 0) return pObjCurrent->ObjPrev()->ObjNameChg(); if (wichObj == 1) return pObjCurrent->ObjNameChg(); if (wichObj == 2) return pObjCurrent->ObjNext()->ObjNameChg(); } return "-"; } //>>>>>VOID REFRESHQUEUE() void refreshQueue() // aktualisiert die ObjectQueue-Instanz { Form1->EditFirst->Text = pObjFirst->ObjNameChg(); Form1->EditFinal->Text = pObjFinal->ObjNameChg(); Form1->EditCount->Text = IntToStr(ObjCount); Form1->EditPrev->Text = showObjName(0); Form1->EditCurrent->Text = showObjName(1); Form1->EditNext->Text = showObjName(2); } protected: Object *pObjFirst; Object *pObjFinal; Object *pObjCurrent; int ObjCount; }; //-------INSTANZEN ObjectQueue queue_one; void __fastcall TForm1::ButtonAddClick(TObject *Sender) { if (EditNew->Text != "") { Object *pObjNew; pObjNew = new Object; pObjNew->ObjNameChg(EditNew->Text); queue_one.addObj(pObjNew); queue_one.refreshQueue(); } } //--------------------------------------------------------------------------- void __fastcall TForm1::ButtonDestroyClick(TObject *Sender) { queue_one.destroyObj(); queue_one.refreshQueue(); } //--------------------------------------------------------------------------- void __fastcall TForm1::ButtonNextClick(TObject *Sender) { queue_one.gotoNextObj(); queue_one.refreshQueue(); } //--------------------------------------------------------------------------- void __fastcall TForm1::ButtonLastClick(TObject *Sender) { queue_one.gotoPrevObj(); queue_one.refreshQueue(); } //---------------------------------------------------------------------------
Was mir außerdem nicht gefällt sind folgende Zeilen aus der Object-Klasse:
*
Object *ObjNext(int toDo = 0, Object *pObjNewNext = NULL)
Object *ObjPrev(int toDo = 0, Object *pObjNewPrev = NULL)
*
Wenn ich diese Funktionen ohne Parameter aufrufe, geben sie mir wie gewünscht das nächste / vorherige Element der Liste an. Wenn ich allerdings das nächste / vorherige Element ändern will, muss ich für den Integer toDo jedesmal einen Wert setzen.
Bin für jede Hilfe und sonstige Tipps, wie man das ganze verbessern kann, dankbar.
-
Hallo,
Ich will nun von mehreren anderen Klassen aus Zugriff auf ein und dieselbe Liste haben. Die Anzahl der Klassen, die dabei Zugriff auf die Liste haben, soll quasi unbeschränkt sein.
Ich möchte dir nichts falsches sagen, aber kann es sein, dass du ein Synchronisationsproblem bekommst? Schau dir mal folgenden Beitrag an:
http://www.c-plusplus.net/forum/viewtopic.php?t=79797MfG
-
ich glaube auch, daß es für deine Anforderungen nicht sehr sinnvoll ist dir die aktuelle Position innerhalb einer Queue in der selbigen zu merken, da diese ja von verschiedenen anderen Objekten anderer Klassen bearbeitet wird.
Zu deiner zweiten Frage: kennst du Elementinitialisierer?
-
@EdiRitter
Bin noch nicht so in der Materie. In deinem Link beschreibt HumeSikkins (letzter Beitrag, erste Seite) glaub ich das, was mir auch passieren könnte, stimmt's? Ich kann damit allerdings nicht wirklich viel anfangen, da mir die Erfahrung fehlt.@freshman
Richtig, nur wie macht man's sonst am besten?
Und zu deiner Frage sag ich einfach mal: Nö(Zumindest hab ich den Begriff nie gehört...
)
Ich hatte mir folgendes überlegt: Da später noch weitere Datenstrukturen etc. (neben der Liste) dazu kommen sollen, die ebenfalls von mehreren Klassen gleichzeitig benutzt werden können, brauche ich eine übergeordnete Klasse, die das ganze managed. Ich hab dabei außerdem versucht jeder Datenstruktur eine sogenannte Account-Liste zu gegeben, in welche sich jede Klasse, die Zugriff auf die jeweilige Datenstruktur haben will, eintragen muss. In diesem Account sind dann z.B. auch die jeweiligen Zeiger gespeichert. Das Problem ist nur, dass es in der Theorie schön und gut ist, in der Praxis... naja... verwirrt beschreibt meinen Zustand dann wohl am besten
-
Hallo,
Ich will nun von mehreren anderen Klassen aus Zugriff auf ein und dieselbe Liste haben. Die Anzahl der Klassen, die dabei Zugriff auf die Liste haben, soll quasi unbeschränkt sein.
Dein Problem lässt sich mittels Semaphoren lösen. Hierbei handelt es sich um ein Standard - Synchronisationsproblem: Reader - Writer, d.h. 1 Writer, beliebig viele Reader. Ich habe allerdings keine Ahnung wie man die Semaphore in VC++ implementiert, wir haben bisher stets mit LINUX gearbeitet und dort das Ganze mittels Shell - Skript gelöst.
// Pseudo Code seminit(datei, 1); seminit(synchro, 1); // Reader, Writer gleichberechtigt behandeln. seminit(ausschluss, 1); int lz = 0; // lesezähler Writer() { while(true) { P(synchro); P(ausschluss); // schreiben V(ausschluss); V(synchro); } } Reader() { while(true) { P(synchro); P(ausschluss); lz++; if(lz==1) P(datei); V(ausschluss); V(synchro); // lesen P(ausschluss); lz--; if(lz==0) V(datei); V(ausschluss); } }
Solltest du dein Programm wie beschrieben weiterentwickeln, kommst du um die Semaphore nicht herum
. Du kannst bei google nach 'Semaphoren' und 'Betriebssysteme' suchen.
MfG
-
Danke!
Das ist doch schonmal was, mit dem ich was anfangen kann.