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

drakon

Supermoderator

Beiträge: 6 513

Wohnort: Schweiz

Beruf: Entrepreneur

  • Private Nachricht senden

11

07.12.2009, 21:13

Naja. Ich würde sogar sagen, dass das nicht mal ein Problem darstellt, denn die grafischen Aufrufe sind meist so lahm im Verhältnis zu einfachen Funktionscalls (auch Polymorphe), dass es wahrscheinlich kaum ins Gewicht fällt. Aber das müsste man halt testen.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

12

07.12.2009, 22:01

Der zusätzliche overhead von nem virtual im vergleich zu nem normalen function call entspricht in etwa einem Arrayzugriff. Das is für 99.9% von allem Code den du in deinem Leben jemals schreiben wirst irrelevant ;)

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

13

07.12.2009, 22:23

Re: Templates vs. Interface

Zitat von »"Laguna"«

Jedoch möchte/kann ich für die organisation nicht die std-Container benutzen, da ich mir einige zusätzliche Funktionen wünsche. So z.B. dass jedes Spielobjekt über seinen Bezeichner identifizierbar ist oder dass Objekte serialisiert werden können, für Speichern/Laden (und einige andere Sachen)


Mit std::map kannst du deine Objekte über Bezeichner ansprechen und das Serialisieren müssen sowieso die Objekte implementieren...

Zitat von »"Laguna"«

Mir erscheinen gerade zwei Wege sinnvoll: Entweder ich baue mir einer Vererbungshierarchie auf: "GameObject" und dies als Interface für eine Speicherung.

Alternativ eine Templateklasse, die diese Objekte verwaltet.

Gibt es darüber hinaus einen anderen Weg? Wie stehen die Meinungen zu diesen zwei Möglichkeiten? Wo seht ihr Vor- und Nachteile bzw Stolperfallen?


Wie schon gesagt wurde: Templates und Vererbung schließen sich nicht aus. Genaugenommen sind das eigentlich zwei sehr unterschiedliche Dinge. Außerdem versteh ich nicht warum du dich zwischen einer Vererbungshierarchie und einer Klasse zum Verwalten der Objekte entscheiden musst. Auch mit Vererbung wirst du wohl irgend eine Form von Container brauchen um deine Objekte aufzunehmen!?

Du kannst dir z.B. auch einen Objektcontainer als template basteln der intern eine std::map verwendet und dir ein paar Komfortfunktionen wie du sie haben willst bietet...

Zitat von »"Laguna"«

Meine Meinung dazu: Eine saubere Vererbungshierarchie incl Interfaces ist schön zu lesen. Auch lassen sich mit Factoryklassen alle Aspekte sehr schön verpacken und von Aussen sieht man nurnoch das, was man sehen soll.
Allerdings kann man sich damit auch recht schnell in Sackgassen manövrieren. Zusätzlich kommt einiges an Tipparbeit auf einen zu, sowie die Performanceeinbußen durch VTables.


Die Performanceeinbußen sind für Dinge wie Serialisieren vermutlich nichtmal messbar. Ich denke jedenfalls nicht dass du vorhast mehrere tausendmal pro Sekunde zu Serialisieren...

Zitat von »"Laguna"«

Templates glänzen durch ihre Schlichtheit, eine gute Performance (durch Instancing zu Compilezeit, usw.), jedoch ist der Syntax oft kryptisch und für aussenstehende deutlich schwerer zu verstehen als ein Interface - Factory zusammenhang. Zusätzlich ist die Sichtbarkeit nicht so schön gelöst, wie bei Interfaces.


Wie schon gesagt sind templates ein grundsätzlich anderes Konzept als Vererbung und das eine schließt das andere nicht wirklich aus. Aber die Syntax und vor allem die Compilerfehlermeldungen werden in der Tat schnell kryptisch.

14

07.12.2009, 23:07

@ CBenni::O:
Vielen Dank für das Zitat! ;)

@ drakon, dot:
Volle Zustimmung. Es ist recht unwahrscheinlich, dass virtuelle Funktionen ein Problem darstellen. Das heisst natürlich nicht, dass man sich nicht mehr achten muss, aber genauso wenig sollte man auf Abstraktion verzichten, weil man irrtümlicherweise denkt, man habe die Performance nötig. Das gilt übrigens nicht nur für virtuelle Funktionen.

Um mich aus einem anderen Thread zu zitieren:

Zitat von »"Nexus"«

Was mich stört, ist der verbreitete Irrglaube, dass Objektorientierung und Abstraktion schlechtere Laufzeitverhältnisse implizieren. Virtuelle Funktionen sind zum Beispiel ein weiteres Schlagwort für Langsamkeit. Sehr selten denkt dabei jemand daran, dass auch auf tieferer Abstraktionsebene eine Auswahl zwischen verschiedenen Ablaufpfaden realisiert werden muss - ob das schlussendlich if, switch, selbst gebaute Funktionszeiger-Sprungtabellen oder gleich "richtige" virtuelle Funktionen sind, spielt im Allgemeinen keine grosser Rolle mehr.

15

08.12.2009, 17:36

Re: Templates vs. Interface

Zitat von »"dot"«

Mit std::map kannst du deine Objekte über Bezeichner ansprechen und das Serialisieren müssen sowieso die Objekte implementieren...

Eine Map möchte ich deshalb nicht verwenden, da die Objekte selbst schon die Bezeichner enthalten, was meiner Meinung nach in einer OOP-Umgebung auch Sinn macht.

Zitat von »"dot"«

Wie schon gesagt wurde: Templates und Vererbung schließen sich nicht aus. ...

Es geht hier weniger um die Vererbung als um die Benutzung eines Interfaces, das über Vererbung erstellt wird.


Zitat von »"dot"«

Du kannst dir z.B. auch einen Objektcontainer als template basteln der intern eine std::map verwendet und dir ein paar Komfortfunktionen wie du sie haben willst bietet...
Wie gesagt, es wird so oder so auf eine Wrapper-klasse hinauslaufen. Wie diese jedoch am geschicktesten aufzubauen ist, ist meine Frage. Also, ob ich Interfaceklassen speichere oder eben eine Templateklasse erstelle, die mir die entsprechenden Objekte hält.


Ich denke, ein Beispiel wird etwas Licht ins Dunkel bringen:

Ich möchte Listen folgender Objekte anlegen (Auswahl):

- Einfache graphische Details, wie Grasbüschel oder Flares
- Hindernisse, Mauern, Steine, die mit bestimmten Objekten Kollision verursachen
- Schüsse (Kugeln), die Spieler wie Gegner verletzen können
- Charaktere
* Den Spieler
* NPCs (laufen, reden, handeln, simple AI)
* Gegner (laufen, schiessen, sterben, AI)

Im Grunde sähe die Schnittstelle (Interface oder Template) wie folgt aus:
- Fester und eindeutiger Name, zusätzlich evtl. Typ des Objekts (wahlweise Typetraits, String, ClassID, UUID)
- Input
- Update
- Draw

Über die Listen möchte ich folgendes erreichen können:
- Beliebig Objekte Löschen und Hinzufügen
- Ein spezielles Objekt heraussuchen
- Einzigartikgeit der Objekte sicherstellen

Über diese Liste(n) muss die Gamelogik definiert werden können, d.h. ich muss Objekt-Objekt Prüfungen vornehmen können.


Das ganze führt zu ner Reihe von Lösungsmöglichkeiten, jedoch auch zu einer Reihe Problemen.

Erstelle ich mir eine Liste, die alles verwaltet oder für jeden Typ eine eigene Liste. Wie müssen die Listen dann aufgebaut sein(Template/Interface/whatever).Wie realisiere ich die einzelnen Punkte am elegantesten. Gerade der letzte (Stichwort DoubleDispatching) erscheint mir wichtig.

So Far...

Laguna

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

16

08.12.2009, 18:13

Re: Templates vs. Interface

Zitat von »"Laguna"«

Eine Map möchte ich deshalb nicht verwenden, da die Objekte selbst schon die Bezeichner enthalten, was meiner Meinung nach in einer OOP-Umgebung auch Sinn macht.


OK, das ist ein Argument. Allerdings wird es dann halt drauf hinauslaufen dass du idealerweise selber eine ähnliche Datenstruktur (binärer Suchbaum) implementieren musst. Außerdem könnte man für den Fall (Key im Objekt) evtl. ein std::set verwenden.

Zitat von »"Laguna"«

Wie gesagt, es wird so oder so auf eine Wrapper-klasse hinauslaufen. Wie diese jedoch am geschicktesten aufzubauen ist, ist meine Frage. Also, ob ich Interfaceklassen speichere oder eben eine Templateklasse erstelle, die mir die entsprechenden Objekte hält.


Ich seh noch immer nicht ganz wo genau du jetzt templates eigentlich verwenden willst. Der Container wird immer nur GameObject Dinger enthalten (bzw. halt Pointer drauf), damit ist es fraglich ob der ein template sein muss. Und für deine Objekte wirst du so oder so ein gemeinsames Basisinterface benötigen wenn du alle in einen gemeinsamen Container packen willst!?

EDIT: Hab schlampig gelesen, wenn du für jeden Typ einen eigenen Container haben willst wird es natürlich gescheit sein ein template anzulegen. Allerdings macht das die Dinge evtl. unnötig kompliziert (was immer du tust, du musst dann dauernd alle Container abklappern). Ob das sinvoll ist hängt wohl sehr stark von der konkreten Anwendung ab...

17

08.12.2009, 18:29

Ich persönlich stelle mir "prüfe alle Elemente in Liste 1 gegen alle Elemente in Liste 2" deutlich einfacher vor, als "Prüfe alle Elemente in einer Liste auf ihren typ und rückwirkend auf sämtliche Kombinationen mit möglichen anderen Typen"
Siehe hier

So Far...

Laguna

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

18

08.12.2009, 18:39

Zitat von »"Laguna"«

Ich persönlich stelle mir "prüfe alle Elemente in Liste 1 gegen alle Elemente in Liste 2" deutlich einfacher vor, als "Prüfe alle Elemente in einer Liste auf ihren typ und rückwirkend auf sämtliche Kombinationen mit möglichen anderen Typen"
Siehe hier


Gut das hab ich aus deiner Frage nicht herausgelesen (ich ging davon aus dass du sowieso jedes gegen jedes Objekt testen willst). Der Sinn des Double Dispatch Pattern ist ja aber eben gerade das Problem zu lösen das man hätte wenn alles in einem gemeinsamen Container liegt!?
Anyway, die Lösung mit mehreren Containern erscheint in diesem Licht natürlich nicht verkehrt...

19

08.12.2009, 18:52

Ich hab DD noch nie implementiert, hab lediglich ein wenig im Netzt und aus Meyers Effective C++ einen Großteil meiner Infos. Dort sah das ganze aber nicht übermäßig hübsch aus, weswegen ich solche Konstrukte bis jetzt vermieden habe.
Zumal ich mich ja nicht auf nur 3 Typen beschränken will ^^

Prinzipiell, eher eine große Liste, in der dann alles rumschwimmt oder halt verschiedene kleinere Listen?

Naja, mal sehn, es kommen bestimmt noch ein paar gute Ideen. :-)

Laguna

20

08.12.2009, 20:54

Re: Templates vs. Interface

Zitat von »"Laguna"«

Ich möchte Listen folgender Objekte anlegen (Auswahl):

- Einfache graphische Details, wie Grasbüschel oder Flares
- Hindernisse, Mauern, Steine, die mit bestimmten Objekten Kollision verursachen
- Schüsse (Kugeln), die Spieler wie Gegner verletzen können
- Charaktere
* Den Spieler
* NPCs (laufen, reden, handeln, simple AI)
* Gegner (laufen, schiessen, sterben, AI)
Gut, genau so habe ich mir das vorgestellt. Es scheint so, als ob mein Entwurf gar nicht so schlecht passen würde. Sowas wie "Objekt" könntest du als Basisklasse nehmen, von dem du dann z.B. kollidierbare Objekte ableitest, diese werden wiederum in Gegner, Spieler, Projektile unterteilt (so habe ich das in einem Jump'n'Run gemacht).

Zitat von »"Laguna"«

Im Grunde sähe die Schnittstelle (Interface oder Template) wie folgt aus:
- Fester und eindeutiger Name, zusätzlich evtl. Typ des Objekts (wahlweise Typetraits, String, ClassID, UUID)
- Input
- Update
- Draw
Das sehen zwar nicht alle gleich, aber ich persönlich finde es wichtig, Grafik und Logik zu trennen. Das bedeutet, ein Gegner weiss nicht, zu welchem Fenster er gehört oder wie er gezeichnet wird. Für jene Aktionen wären separate Klassen zuständig. Einerseits werden dann grafik-spezifische Dinge an einem Ort geregelt, andererseits erhältst du durch die Unabhängigkeit beider Komponenten zusätzliche Flexibilität. Du kannst eine davon austauschen, ohne die andere anzutasten. Auch die Zentralität hat einen Vorteil: Du kannst zum Beispiel an einem Ort alle Grafikaufrufe unterbrechen, oder irgendeine spezielle Operation für alle grafischen Objekte einführen.

Zitat von »"Laguna"«

Ich persönlich stelle mir "prüfe alle Elemente in Liste 1 gegen alle Elemente in Liste 2" deutlich einfacher vor, als "Prüfe alle Elemente in einer Liste auf ihren typ und rückwirkend auf sämtliche Kombinationen mit möglichen anderen Typen"
Da hast du absolut Recht. Wenn du bereits zur Compilezeit Typen trennen kannst und dadurch Vorteile erhältst, dann nutze die Möglichkeit! Denn Abstraktion dient dazu, mehrere ähnliche Objekte einheitlich zu behandeln. Wenn diese darauf hinausläuft, dass wieder Fallunterscheidungen ins Spiel kommen, hat man das Prinzip nicht ganz verstanden.

Du kannst ruhig einen Container für jeden Objekttyp schreiben (sofern du irgendwo noch eine sinnvolle Grenze findest, ab der du nicht mehr weiter aufteilst – soll heissen, keine eigene Klasse für Gräser, Blätter und am Boden liegende Äste ;)). Auch dass du dann mehrmals iterieren musst, ist kein Problem. Wenn das oft vorkommt, kannst du auch dafür eine generische Funktion schreiben.

Ein weiterer Vorteil dieser Vorgehensweise besteht darin, dass du gleich automatische Objekte in Container packen kannst und keine Umwege über polymorphe Zeiger gehen musst. Hüte dich so gut es geht vor rohen, besitzenden Zeigern in STL-Containern, denn diese birgen nicht wenige Risiken.

Werbeanzeige