Mal wieder Zeit für ein paar C++ Fragen

  1. ich will eine lange liste aus elementen haben, am besten indem ein element einen zeiger auf das nächste hat. nun haben die elemente aber verschiedene typen. wie kann ich das elegant realisieren?

  2. Was ist eigentlich die Bessere Lösung, einen Array aus Elementen zu definieren, oder ein Element, das wiederum einen Zeiger auf ein weiteres Element enthält, so wie ich es vorhatte?

  3. Ist es sinnvoll, in den Konstruktor eines Objekts den Befehl delete(this) zu schreiben, oder sollte man das dort erledigen, wo man den pointer auch erzeugt hat? (vorrausgesetzt natürlich, das objekt ist ein zeiger)

  4. Als ich mir den Source-Code von Half-Life angeguckt hab, habe ich festgestellt, dass in einigen Funktionen Pointer erzeugt werden (beispielsweise für ein Geschoss), die nicht gelöscht werden, wenn die funktion, die sie erzeugt hat, verlassen wird. Ausserdem muessen einige Funktionen dieser Objekte auch später noch aufgerufen werden (ein geschoss sollte beispielsweise weiterfliegen), aber es existiert ja soweit ich weiss kein Handler mehr für das Objekt. Wie wird so etwas realisiert? (durch das intensivere studieren des Codes bin ich auch nicht weitergekommen, war nur verwirrt :smile:

Kann mir jemand bei einer oder mehreren dieser Fragen helfen?
Danke schonmal im Vorraus!

Hallo Reaper,

zu 1. und 2. kann ich helfen.

  1. ich will eine lange liste aus
    elementen haben, am besten indem ein
    element einen zeiger auf das nächste hat.
    nun haben die elemente aber verschiedene
    typen. wie kann ich das elegant
    realisieren?

Dies könntest Du über Unions realisieren, oder mittels Type-Casting.

Wenn Du Unions nimmst, dann ist das ganze etwas sauberer, es fällt nicht sehr auf, daß die Elemente verschiedene Typen haben. Der Nachteil ist, daß jede Variable immer so groß ist wie die größte Variable in der Union:

union NumericType
{
char cValue;
int iValue;
long lValue;
};

Hier würde also immer Platz für ein long reserviert werden.

Wenn Du Typecasting benutzt, dann kannst Du das umgehen. Du legst ein „leer“-Struct an, in dem nur der Zeiger auf das nächste Element steht und der Typ als Integer-Zahl (oder Enum).

Dann legst Du für jeden unterschiedlichen Typ ein Struct an, daß gleich anfängt, aber
dann unterschiedlich weitergehen kann.

Anhand der Typen-Nummer kannst Du dann entscheiden, wie der Rest behandelt werden kann. Sieh’ Dir am besten mal das folgende Beispiel an:

#include

struct LEER
{
LEER *lpNext;
int iType; // = 0
};

struct BEISPIEL1
{
LEER *lpNext;
int iType; // = 1
int iBeispiel1;
};

struct BEISPIEL2
{
LEER *lpNext;
int iType; // = 2
char cBeispiel2;
};

LEER *lpStart;

void CreateList()
{
BEISPIEL1 *lpNew1 = new BEISPIEL1;
LEER *lpNewLeer = new LEER;
BEISPIEL2 *lpNew2 = new BEISPIEL2;

lpNew1->lpNext = (LEER *)lpNewLeer;
lpNewLeer->lpNext = (LEER *)lpNew2;
lpNew2->lpNext = NULL;

lpNew1->iType = 1;
lpNewLeer->iType = 0;
lpNew2->iType = 2;

lpStart = (LEER *)lpNew1;
}

void DeleteList()
{
LEER *lpCur,*lpNext;

lpCur = lpStart;

while (lpCur!=NULL)
{
lpNext = lpCur->lpNext;
delete lpCur;
lpCur = NULL;
lpCur = lpNext;
}
}

void main()
{
BEISPIEL1 *lpBsp1;
BEISPIEL2 *lpBsp2;
LEER *lpLeer;
LEER *lpCur;

CreateList();

lpCur = lpStart;

while (lpCur!=NULL)
{
switch(lpCur->iType)
{
case 1:
lpBsp1 = (BEISPIEL1 *)lpCur;
printf(„Eintrag ist vom Typ BEISPIEL1\n“);
break;
case 2:
lpBsp2 = (BEISPIEL2 *)lpCur;
printf(„Eintrag ist vom Typ BEISPIEL2\n“);
break;
default:
lpLeer = lpCur;
printf(„Eintrag ist vom Typ LEER oder unbekannt\n“);
break;
}
lpCur = lpCur->lpNext;
}

DeleteList();
}

  1. Was ist eigentlich die Bessere Lösung,
    einen Array aus Elementen zu definieren,
    oder ein Element, das wiederum einen
    Zeiger auf ein weiteres Element enthält,
    so wie ich es vorhatte?

Das kommt darauf an, was Du machen möchtest. Wenn Du häufig ungeordnet auf verschiedene Elemente zugreifen mußt (random access), dann ist ein Array besser, weil Du eben direkt über den Index auf ein Element zugreifen kannst. Der Prozessor kann die Adresse leicht über Index*Struct-Größe errechnen.

Bei einer verketteten Liste dagegen muß man immer am Anfang anfangen und sich dann weiterbewegen, bis man das gesuchte Element gefunden hat. Das ist natürlich wesentlich aufwendiger.
Allerdings kann man bestimmte Sachen, wie z. B. Sortieren, Löschen und Einfügen von Einträgen bei Linked Lists leichter machen, da man nur die Pointer ändern, nicht aber die ganzen Structs kopieren muß.

Bei 3. und 4. kann ich leider nicht helfen. Aber wo bekommt man den Half-Life Source?

–Mathias Ricken

  1. Ist es sinnvoll, in den Konstruktor
    eines Objekts den Befehl delete(this) zu
    schreiben, oder sollte man das dort
    erledigen, wo man den pointer auch
    erzeugt hat? (vorrausgesetzt natürlich,
    das objekt ist ein zeiger)

wennst das im constructor machst, wird warscheinlich das programm abstürzen.
wahrscheinlich hast das Objekt mit new gemacht und denau auf der ebene mußt es natürlich auch wieder deleten.

wennst in einem constructor draufkommst, daß sich das objekt nicht initialisieren äßt (kein speicher, file nicht gefunden, …) dann empfehle ich mit exception aus dem constructor raus zu springen und um das new ein try{new object;}catch(…){printf(„error detected“); object=NULL;} zu machen.

  1. Als ich mir den Source-Code von
    Half-Life angeguckt hab, habe ich
    festgestellt, dass in einigen Funktionen
    Pointer erzeugt werden (beispielsweise
    für ein Geschoss), die nicht gelöscht
    werden, wenn die funktion, die sie
    erzeugt hat, verlassen wird.

normalerweise erzeugt man objekte schon dafür, daß man sie nachher längere zeit verwenden kann. d.h. halflife speichert die objecte entweder in einer liste oder in einem array. such mal nach „delete“, vielleicht hilft dir das weiter???

  1. ich will eine lange liste aus
    elementen haben, am besten indem ein
    element einen zeiger auf das nächste hat.
    nun haben die elemente aber verschiedene
    typen. wie kann ich das elegant
    realisieren?

Man schreibe eine Basisklasse Node mit zwei
Variablen:
Node* m_pPrevious ;
Node* m_pNext ;

Die Methoden wie „append“, „getPrevious“,
„getNext“, „setPrevious“ und „setNext“,
sowie den „constructor“ und den
„destructor“ sollte man jetzt schreiben.
Der destructor sollte als „virtual“
declariert sein und man könnte durch alle
Zeiger wandern und die dran hängenden
Objekte löschen. adurch kann man den
"delete Befehl wie im Beispiel unten
verwenden.

Definiert man nun eine Klasse Test mit

class Test : public Node
{
/* Deine Daten */
} ;

…besitzt diese Klasse die Möglichkeit der
Verzeigerung. Nun definiert man eine
Liste mit verschiedene Klassen, die
von Node vererbt sind:

Node* pList = new Test() ;
pList->append( new Test() ) ;
pList->append( new TestXYZ() ) ;
pList->append( new TestABS() ) ;

// räumt sauber auf wegen dem
// destructor von Node
delete pList ;

Wenn die Klasse Node gewünscht ist,
kann ich sie gerne zusenden !

  1. Was ist eigentlich die Bessere Lösung,
    einen Array aus Elementen zu definieren,
    oder ein Element, das wiederum einen
    Zeiger auf ein weiteres Element enthält,
    so wie ich es vorhatte?

Das ist sowohl eine Zeitfrage, als
auch von der Situation abhängig.

  • Wenn der Array eine feste Größe hat oder
    die Größe sich selten ändert, dann
    ist ein Array effektiv.
  • Beim Herauslöschen eines Elements und
    der Veränderung der Größe durch Einfügen
    oder Anhängen würde ich eine Liste
    vorziehen.

Half-Life Source
Danke für deine Antwort

Ein deutscher FTP-Server ist ftp.gigabell.net/pub/games/idgames/

irgendwo in dem verzeichnis, eventuell noch ein unterverzeichnis das Ding nennt sich HL-SDK (standard developers kit), allerdings ist der code für die engine und so natürlich nicht drin, aber der für den spielablauf. (soweit ich weiss brauch man für singleplayer das professional dev.kit)

Eine Liste für Downloadsites gibts hier:
http://dl.fileplanet.com/dl/dl.asp?planethalflife/wa…

infos gibts in den foren von www.planethalflife.com und bei www.contaminated.net/wavelength

Viel Spass,
Reaper82

wennst das im constructor machst, wird
warscheinlich das programm abstürzen.
wahrscheinlich hast das Objekt mit new
gemacht und denau auf der ebene mußt es
natürlich auch wieder deleten.

Oops, ich meinte natürlich Destruktor

  1. Ist es sinnvoll, in den Konstruktor
    eines Objekts den Befehl delete(this) zu
    schreiben, …

Wofür ist dieser Code? delete(this) und dann noch im Konstruktor drin?

Meint das dass das löschen auf die momentan ausgeführte Funktion oder Elementfunktion angewendet werden soll??