Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

propper

Frischling

  • »propper« ist der Autor dieses Themas

Beiträge: 21

Wohnort: Internet

  • Private Nachricht senden

1

27.01.2014, 20:23

[C++] Von Liste mit Basisklassen auf die Vererbten Klassen-Funktionen zugreifen

Hallo,
ich bin mit wenigen Monaten Erfahrung noch ein wenig neu in C++, habe aber bereits einige Projekte fertiggestellt (bzw. angefangen :D ). Deswegen bin ich mir auch nicht sicher, ob ich den Titel richtig formuliert habe.


Nun zum Problem:
Ich programmiere derzeit ein Spiel, das, wie die meisten anderen Spiele, den Rhythmus "HandleEvents -> Update -> Render" durchläuft.
Es gibt eine Basisklasse, in der diese Funktionen virtuell deklariert sind und von der alle Objekte im Spiel erben.
Nun habe ich natürlich eine Liste mit dem Datentyp MainObject* angelegt (MainObject ist die Basisklasse aller Objekte). In dieser Liste sind alle Objekte des Spieles gespeichert und in Jedem Frame Wird der Rhythmus "HandleEvents -> Update -> Render" einmal für jedes Objekt in der Liste angewendet.
Die Liste ist so Deklariert:

C-/C++-Quelltext

1
2
std::list<MainObject*> ObjectList;
std::list<MainObject*>::iterator ObjectIt;


Ich rufe in der Liste die verschiedenen Funktionen folgendermaßen auf (Bsp. Update):

C-/C++-Quelltext

1
2
3
4
5
6
for(ObjectIt = ObjectList.begin(); ObjectIt != ObjectList.end(); ObjectIt++)
{
    MainObject *pMainObject;
    pMainObject = *ObjectIt;
    pMainObject->Update(/* Args */);
}


Da manche Objekte natürlich auch Daten anderer Objekte benötigen, übergebe ich bei Update auch immer die Objekt-Liste (und die FrameTime für Bewegungen):

C-/C++-Quelltext

1
void Update(float FrameTime, std::list<MainObject*> ObjectList);


Wenn ich die Liste habe, habe ich zwar auch alle Objekte mit Vererbungen (oder nicht?), aber (!) wie kann ich auf die Funktionen einzelner unterschiedlicher Objekte dann zugreifen, auch wenn die bestimmten funktionen nicht in der Baisklasse definiert sind? Denn z.B. hat ein Auto ja nicht die Variable Blätteranzahl, wie evtl. ein Baum, die aber beide von der selben Basisklasse (MainObject) erben.
Da der Iterator ja auf die Liste mit dem Datentyp MainObject* abgestimmt ist, zeigt es mir ja auch logischerweise keine Member von dem Baum oder so an. Aber wie kann ich denn auf die Member solcher klassen zugreifen?
Habe schon folgendes Probiert (GetID() gibt hier Beispielsweise nur Aufschluss darüber, um was für ein Objekt es sich handelt, und ob es das richtige für die Berechnungen damit ist. Die ID ist einmalig in der Liste):

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Pointer für das Objekt erstellen
Baum *pBaum;
//Pointer auf das Objekt richten
for(ObjectIt = ObjectList.begin(); ObjectIt != ObjectList.end(); ObjectIt++)
{
    if(ObjectIt->GetID() == "Baum")
    {
        /*Dies Funktioniert ligischerweise nicht, da *ObjectIt ja nicht immer ein Baum ist, sonder
        evtl. ja auch ein Auto ist. Dies schließt die if()-Abfrage zwar aus, weiß der Compiler aber
        ja nicht. Und ich weiß nicht, ob das sonst auch funktionieren würde. */
        pBaum = *ObjectIt;
    }
}
//Funktion ausführen, die nicht in der Basisklasse definiert ist
pBaum->BaumFunktion(/* Args */);


Nun, wie könnte man dieses Problem lösen, also das ich von der Bestimmten Klasse auf eine Funktion zugreife, die nicht in der Basisklasse ist? Oder geht das überhaupt gar nicht?

Danke schon mal für eure Antworten :thumbup:

mfg propper

FSA

Community-Fossil

  • Private Nachricht senden

2

27.01.2014, 20:28

Warum sollte man das machen wollen? Wenn du auf die Parameter eines Objektes Zugriff haben möchtest, dann musst du auch dieses Objekt bzw. einen Zeiger auf das Objekt haben.

Willkommen im Forum :thumbup:

Zitat

Der RCCSWU (RandomCamelCaseSomtimesWithUndersquare) Stil bricht auch mal mit den veraltet strukturierten Denkmustern und erlaubt dem Entwickler seine Kreativität zu entfalten.

NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

3

27.01.2014, 20:31

Die Interfaces sind gerade dazu da, dass man alles gleich behandeln kann. Wenn man mit RTTI anfängt ist das immer ein Zeichen von Fehlern im Design und es macht so gut wie alle Vorteile des Interfaces wieder zunichte.
Gib den Objekten die nötigen Informationen bzw. Quellen für aktuelle Informationen bei der Instanziierung mit. Alles was die abgeleiteten Klassen betrifft sollte auch darin geregelt werden.

Edit: kleiner Tipp am Rande: Vermeide Iteratoren als Member. Sie werden viel zu häufig ungültig und man kann selten garantieren, dass sie gültig bleiben.
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

propper

Frischling

  • »propper« ist der Autor dieses Themas

Beiträge: 21

Wohnort: Internet

  • Private Nachricht senden

4

27.01.2014, 20:33

Da Objekte jeglicher art in dieser Liste sind und wenn ich für jedes Objekt, was z.B. die Geschwindigkeit eines Autos braucht um zu berechnen, was es als nächstes tut, ein Argument extra einzeln in die z.B. Update-Funktion reinhaue, dann ist die nach einer zeit schon mal ziemlich voll, da man von virtuellen Funktionen doch die Argumente-Liste nicht verändern kann (oder?) und eben die Update-Funktion schon in der Basisklasse definiert ist.

//Edit:
wenn dies nicht so dafür geeignet ist, wie kann man dennoch gewünschte Parameter übergeben, ohne die Update-Funktion mit vielen Argumenten vollzuhauen? Denn nach 5 Objekten ist dies ja schon sehr unübersichtlich.

NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

5

27.01.2014, 20:37

Gib den Objekten die nötigen Informationen bzw. Quellen für aktuelle Informationen bei der Instanziierung mit.
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

propper

Frischling

  • »propper« ist der Autor dieses Themas

Beiträge: 21

Wohnort: Internet

  • Private Nachricht senden

6

27.01.2014, 20:41

d.h. ich soll alle Infos, die ich irgendwann dort verwenden werde, egal welches Objekt, in die Basisklasse Packen und bei dem erstellen des Objektes alle Infos für das jeweilige Objekt definieren?

patrick246

Treue Seele

Beiträge: 328

Wohnort: nahe Heilbronn/BW

Beruf: TG Profil Informatik-Schüler

  • Private Nachricht senden

7

27.01.2014, 20:49

C-/C++-Quelltext

1
void Update(float FrameTime, std::list<MainObject*> ObjectList);

Hier kopierst du die gesamte ObjectList pro Aufruf. Willst du nicht lieber eine const Referenz verwenden?

NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

8

27.01.2014, 20:52

Wenn du alle Objekte in einem einzigen Container steckst kennst du ihren wahren Typ nur bei der Instanziierung der Objekte. Jede abgeleitete Klasse kann einen eigenen Konstruktor definieren. Diesem übergibst du die nötigen Quellen. Wenn bestimmte Objekte eine spezielle Verwaltung benötigen, dann gehören sie nicht (nur) in den Container, der alle Objekte enthält.

Eine List für die Objekte zu verwenden und sie dann noch als Value zu übergeben ist nicht gerade Performant. Besser wären ein vector oder eine map mit der ObjektID als Schlüssel um eine schnelle Suche zu ermöglichen.
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

propper

Frischling

  • »propper« ist der Autor dieses Themas

Beiträge: 21

Wohnort: Internet

  • Private Nachricht senden

9

27.01.2014, 20:59

Meinst du das so:

Erstelle Objekt Baum
Füge Baum in Liste ein

Erstelle Gärtner
Zeige Gärtner den Platz von Baum in Liste
Füge Gärtner in Liste ein

Und dann wird bei jedem Aufruf von Gärtner-Update auf den Gezeigten Platz in der liste zugegriffen?

Oh, Moment ^^
Dann müsste Baum in einer Liste Gespeichert sein, wo man auch weiß, dass es ein Baum ist, also nicht in der Allgemeinen Liste, sehe ich das richtig?

NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

10

27.01.2014, 21:04

Ich würde es so machen.
"Der erste Trunk aus dem Becher der Erkenntnis macht einem zum Atheist, doch auf dem Grund des Bechers wartet Gott." - Werner Heisenberg
Biete Privatunterricht in Berlin und Online.
Kommt jemand mit Nach oMan?

Werbeanzeige