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

1

15.08.2013, 21:28

C++ Objekt einer Klasse Definieren

Hallo!
Ich lese grade das Buch C++ für Spieleprogrammierer von Heiko Kalista und bin grade bei einem Punkt angekommen, der mir den Kopf zerbricht.
In Kaptiel 12 in der die SDL behandelt wird definiert er oft Objekte von Klassen um ihre Funktionen außerhalb der Klasse zu verwenden.
Das sieht wie folgt aus:

#define g_pTimer CTimer::Get ()
class CTimer
{
public:
void GetElapsed ();
//Klassen Stuff
};

und außerhalb der Klasse die Funktion aufrufen (in einer anderen Klasse):

g_pTimer->GetElapsed ();

Nun. Irgendwie wurde das nicht erklärt (oder ich hab sie irgendwie übersprungen, obwohl ich alles doppelt und dreifach gelesen habe).
Wenn ich jzz das selbe versuche bekomm ich vom Compiler erst mal ne Ohrfeige.
"Nicht statische Memberverwiese müssen relativ zu einem bestimmtem Objekt sein"
Ich hab mich blöd getippt als ich versucht habe, mein Problem anders zu lösen aber irgendwie komme ich nicht drum es genauso zu machen wie im Buch.

Und jetzt sitze ich hier und hab kein Plan.
Könnte mir jemand helfen?

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

2

15.08.2013, 21:34

Dieser Code ist furchtbar, vergiss ihn am besten.
Singletons sollte man nicht benutzen, und #define dafür erst recht nicht.
Fehlt die statische Methode CTimer::Get()? Oder ist die unter "Klassen Stuff"?

mint

Frischling

Beiträge: 23

Beruf: Softwareentwickler

  • Private Nachricht senden

3

15.08.2013, 22:12

Das ist kein Singleton (siehe Wikipedia Singleton-Muster), sondern einfach eine Klasse mit einer nicht-statischen Methode. Es macht aber durchaus den Anschein, als sollte es ein Singleton darstellen ;) Dir fehlt dazu aber die Implementierung der statischen Get-Methode. Über diese gibst du das die einzige Instanz dieser Klasse zurück. Sicherstellen, dass es die einzige Instanz ist, kannst Du zum Beispiel, indem Du den Konstruktor privat machst. Dann kann nur die Klasse selbst eine Instanz erzeugen.

Statisch bedeutet, dass die Methode nicht einer Instanz einer Klasse zugeordnet ist. Das Besondere an dieser Methode ist, dass ihre Adresse fest ist, wie bei einer Funktion, daher kann man sie auch über ihre Adresse aufrufen! (Sprich, man muss keine Instanz erzeugen) Das geht bei nicht-statischen Methoden nicht, da die Aufrufadresse vom Aufruf abhängt.

In deinem Fall hast du sie schlicht als nicht-statisch deklariert, daher ist es logisch, dass der Compiler hier meckert. Du müsstest demnach erst eine Instanz dieser Klasse erzeugen und könntest dann über diese die Methode aurufen.

Was Dir der Autor eigentlich zeigen wollte (und ja, es ist grausam), ist, dass du mit Hilfe der Präprozessordirektiven #define Tipparbeit sparen kannst. Der Präprozessor durchläuft deinen Code vor dem Compiler und ist ein reiner "Textverarbeiter". Er ersetzt nachdem er das

#define g_pTimer CTimer::Get ()

gelesen hat überall den String "g_pTimer" in deinem Quelltext durch "CTimer::Get ()". Warum man das gut findet kann ich Dir nicht sagen. Vermutlich weil der Autor es ärgerlich/hässlich findet immer "CTimer::Get ()" zu tippen.

4

15.08.2013, 22:37

Das Macro

#define g_pTimer CTimer::Get ()

ist dafür gedacht damit die Verwendung des Singletons aussieht als ob man eine globale Variable verwendet.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

5

16.08.2013, 06:52

Was natürlich sehr unschön ist, wenn man sogar zwei Sünden statt nur einer benutzt. Es hätte dort auch gleich eine (schlechte) globale Variable verwendet werden können. Aber wie David schon sagte, am besten diesen ganzen Stuss von dieser Stelle vergessen und nie verwenden.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

mint

Frischling

Beiträge: 23

Beruf: Softwareentwickler

  • Private Nachricht senden

6

16.08.2013, 07:27

Ob man Singletons verwenden sollte oder nicht ist immer Geschmackssache. Ich persönlich finde, dass es sinnvolle Anwendungsfälle gibt, sie aber leicht dazu verleiten, sie im Übermaß zu gebrauchen. Man liest immer wieder die Aussage, dass man statt einem Singleton gleich globale Variablen werden kann. Das stimmt leider nicht. Gegenüber einer globalen Variable haben Singletons den entscheidenen Vorteil, dass man sie zustandssicher entwerfen kann.

Ganz plattes Beispiel:
Stell Dir vor Du legst beispielweise den Spielmodus als Ganzzahl ab, von 0 bis 5 z.B. Bei einer globalen Variable hindert dich nichts daran, einfach eine 6 oder -1 hineinzuschreiben und damit dein Programm in einen ungültigen Zustand zu versetzen. Du müsstest dann an allen Stellen, wo Du diese Variable verarbeitest, deinen Code fehlertolerant machen oder dir etwas anderes in der Art einfallen lassen. Zumindest ist es immer eine schlechte Idee, fehlerhafte Eingaben zu akzeptieren und im Nachgang zu versuchen, sie "intelligent" wieder zu korrigieren, das geht in die Hose.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

7

16.08.2013, 09:35

Ob man Singletons verwenden sollte oder nicht ist immer Geschmackssache.
Nein, eigentlich ist das keine Geschmackssache, denn Singleton hat einen einzigen Zweck. Wenn dieser nicht benötigt wird, sind sie Unfug und nichts weiter als versteckte globale Variablen. Da ist eine globale Variable jederzeit sinnvoller als ein Singleton und man würde sie auch direkt als solche erkennen. Wir reden hier schließlich auch nicht von einem einfachen globalen Integer (denn ein Singleton ist keiner!), sondern von einer Klassen-Instanz. Ob ich die per "Classtype::getInstance()" hole oder direkt über den Namen der globalen Variable verwende, macht funktional gesehen keinen Unterschied. Semantisch betrachtet allerdings schon. Die aufgerufenen Methoden sorgen übrigens für den korrekten Zustand des Objekts und da ist es egal, ob dieses ein Singleton ist oder eine globale Variable. Ein Singleton hat nur einen Zweck, nämlich dass es unter keinen Umständen mehr als eine Instanz geben darf. Wird dieser nicht benötigt, ist das Singleton architektonischer Unsinn und eine globale Variable tut es genauso und das deutlich klarer.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

8

16.08.2013, 09:43

Woah. Danke schonmal für die schnellen Antworten. Das macht einiges klarer.
Das was mint sagt kommt mir logisch vor aber ich seh auch nirgendwo, dass die Funktion als statisch deklariert wird ó.o
Also die Header Datei sieht wie folgt aus.

#ifndef TIMER_HPP
#define TIMER_HPP

#include <SDL.h>
#include "singleton.hpp"

#define g_pTimer CTimer::Get ()
class CTimer : public TSingleton<CTimer>
{
public:
CTimer ();
void Update ();
float GetElapsed () {return m_fElapsed;}

private:
float m_fElapsed; // Vergangene Zeit seit dem letzten Frame
float m_fCurTime; // Aktuelle Zeit
float m_fLastTime; // Zeit des letzten Frames

};

#endif

9

16.08.2013, 09:56

Die statische Methode steckt in TSingleton.

10

16.08.2013, 09:59

Hast du die singleton.hpp in deinem Projektordner drinnen?

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#ifndef SINGLETON_HPP
#define SINGLETON_HPP

template <class T>
class TSingleton
{
  protected:

  // Membervariablen
  static T *m_pSingleton;   // Statisches Objekt

  public:

  // Memberfunktionen

  // Destruktor
  //
  virtual ~TSingleton ()
  {
  }

  // Get
  //
  // Aufgabe: Wenn nötig, statisches Objekt erzeugen und
  // Zeiger darauf zurückgeben
  //
  inline static T* Get ()
  {
    // Existiert schon eine Instanz?
    if (!m_pSingleton)
    m_pSingleton = new T;   // Nein, dann neue Instanz erzeugen

    // Zeiger auf die Instanz zurückgeben
    return (m_pSingleton);

  } // Get

  // Statisches Objekt freigeben
  //
  static void Del ()
  {
    // Gab es eine Instanz?
    if (m_pSingleton)
    {
      delete (m_pSingleton);  // Ja, dann freigeben
      m_pSingleton = NULL;    // und Zeiger auf NULL setzen
    }

  } // Del

};

// Die statische Variable erzeugen
//
template <class T>
T* TSingleton<T>::m_pSingleton = 0;

#endif

Werbeanzeige