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

TigerClaw25

unregistriert

1

20.07.2017, 14:26

Vorgehensweise bei Klassen

Hallo Zusammen,
ich habe eine Frage, die ich gerne anhand des Beispiels zum Thema "friend"-Klassen stellen möchte:

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// C++ für Spieleprogrammierer
// Listing 11.12
// Friend-Klassen
//
#include <iostream>

using namespace std;

// Klassen
//

// Klasse für den Tank eines Raumschiffs
//
class CTank
{
    // Die Klasse CAntrieb hat Zugriffsrechte auf
    // die privaten Klassenelemente
    friend class CAntrieb;

    public:
        CTank  (int MaxTreibstoff);
        ~CTank ();

    private:
        int m_Treibstoffmenge;

};

// Konstruktor
//
CTank::CTank (int MaxTreibstoff)
{
    cout << "Neue Tank-Instanz erstellt" << endl;

    // Treibstoffmenge festlegen
    m_Treibstoffmenge = MaxTreibstoff;

} // Konstruktor

// Destruktor
//
CTank::~CTank ()
{
    cout << "Tank-Instanz freigegeben" << endl;

}


// Klasse für einen Antrieb
//
class CAntrieb
{
    public:
        CAntrieb (int Verbrauch);
        ~CAntrieb ();
        void MontiereTank (CTank *pTank);
        void Schub ();

    private:
        CTank *m_pTank;
        int    m_Verbrauch;

};

// Konstruktor
//
CAntrieb::CAntrieb (int Verbrauch)
{
    cout << "Neuer Antrieb erstellt" << endl;

    // Verbrauch festlegen
    m_Verbrauch = Verbrauch;

} // Konstruktor

// Destruktor
//
CAntrieb::~CAntrieb ()
{
    // Montierten Tank entfernen
    if (m_pTank != NULL)
    {
        delete (m_pTank);
        m_pTank = NULL;
    }

    cout << "Antrieb freigegeben" << endl;

} // Destruktor

// MontiereTank
//
void CAntrieb::MontiereTank (CTank *pTank)
{
    // Zeiger auf übergebenen Tank kopieren
    m_pTank = pTank;

    cout << "Tank montiert" << endl;

} // MontiereTank

// Schub
//
void CAntrieb::Schub ()
{
    // Reicht der verbleibende Treibstoff noch?
    if (m_pTank->m_Treibstoffmenge - m_Verbrauch < 0)
    {
        // Nein, also kein Schub mehr möglich
        cout << "Tank ist leer!" << endl;
    }
    else
    {
        // Der Treibstoff reicht noch, also Menge abziehen
        cout << "Antrieb gibt Schub" << endl;
        m_pTank->m_Treibstoffmenge -= m_Verbrauch;
    }

} // Schub

// Hauptprogramm
//
int main ()
{
    // Instanzen für Tank und Antrieb
    CAntrieb *pAntrieb;
    CTank    *pTank;

    // Neuen Tank mit 170 Einheiten Treibstoff erstellen
    pTank = new CTank (170);

    // Neuen Antrieb mit Verbrauch von 35 Einheiten
    // Treibstoff erstellen
    pAntrieb = new CAntrieb (35);

    // Den Tank an den Antrieb montieren
    pAntrieb->MontiereTank (pTank);


    // Antrieb gibt mehrmals Schub
    for (int i=0; i<5; i++)
    {
        pAntrieb->Schub ();
    }

    // Antrieb freigeben. Die Tank-Instanz muss (darf)
    // nicht freigegeben werden, da dies im Destruktor
    // der Antriebsklasse geschieht
    //
    if (pAntrieb != NULL)
    {
        delete (pAntrieb);
        pAntrieb = NULL;
    }
    system("Pause");
    return (0);
}


Meine Frage ist, wie man bei der Erstellung solcher Klassen vorgeht? Zum Beispiel ist "MontiereTank" eine Funktion von "CAntrieb". Hätte man auch "MontiereTank" als Funktion von "CTank" nehmen können? Ob ich den Tank an den Antrieb als Zeiger übergebe oder den Antrieb an den Tank übergebe, sollte ja keine Rolle spielen. Aber gibt es da bestimmte Regeln?

In einem anderen Buchbeispiel gibt es eine Schiffswerft und einen Jaeger, der als Funktion "Andocken" hat. Auch hier hätte man "Andocken" also Funktion der Werft nehmen können, wenn beispielsweise verschiedenen Schiffe andocken sollen.

Und meine zweite Frage bezieht sich auf die Instanzen. In diesem Beispiel erstelle ich meine Instanzen direkt in der Main-Funktion mit "new". Aber in anderen Beispielen werden Instanzen auf dem Stack erstellt und erst mit dem Konstruktur Speicher auf dem Heap reserviert. Gibt es da auch bestimmte Regeln:

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
// Konstruktor
//
CWerft::CWerft (string sName)
{
    cout << "Neue Schiffswerft erstellt" << endl;

    // Name merken
    m_sName = sName;

    // Neuen Jäger erstellen und diesen zum
    // eigenen Schutz andocken lassen
    m_pBewacher = new CJaeger ();
    m_pBewacher->Andocken (this);

} // Konstruktor


// Hauptprogramm
//
int main ()
{
    CWerft ("Werft 01");

    return (0);
}

Ok, in dem Fall kann ich mir die Frage mit dem "new" im Konstruktor selber beantworten, da das Beispiel auf "this" bezogen war. Aber davon abgesehen, gibt es bestimmte Vorgehensweisen?

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

2

20.07.2017, 15:43

Meine Frage ist, wie man bei der Erstellung solcher Klassen vorgeht?
Don't. Ganz ehrlich, fang nicht an mit friend herumzudocktern als sei ein übliches Hilfsmittel. Ist es nicht. Friend sollte sehr selten und am besten gar nicht eingesetzt werden, wenn du mich fragst. Das führt nur zu vernetzten Klassen statt zu einer sauberen Trennung von Funktionalität.

Benutze Stack, wen es geht. Benutze Heap nur dann, wenn es nicht geht. Sprich Heap eigentlich nur bei optionalen Attributen einer Klasse oder wenn du gezwungen bist die Lebensdauer eines Objekts auch über den aktuell gültigen Scopes hinaus verlängern zu müssen und keine Kopien verwenden kannst (was oft bei polymorphen Objekten der Fall ist).
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]

TigerClaw25

unregistriert

3

20.07.2017, 15:45

Das Beispiel orientierte sich am Beispiel aus dem Buch. Aber meine Frage bezog sich nicht auf die friend-Klasse selbst ;)

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

4

20.07.2017, 15:50

Ich wollte es dennoch explizit klar machen.

Zum Thema wie rum: Klar kannst du fast alles so rum oder so rum bauen. Die Frage ist, was mehr Sinn macht. Macht es mehr Sinn einen Tank an einen Antrieb anzubauen oder einen Antrieb an einen Tank? Ich würde einen Tank an einen Motor anschließen, aber er sollte den Tank nicht besitzen, sprich wenn ich den Motor vernichte, würde ich den Tank nicht vernichten. Wieso auch, der is ja vielleicht noch brauchbar und ein separates Teil. Wenn ich beides in einem Auto verbaue und das Auto verschrotte, dann sollten aber natürlich Motor und Tank auch mit Schrott sein, sofern ich ihn nicht vorher explizit ausbaue.
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]

TigerClaw25

unregistriert

5

20.07.2017, 16:22

Das macht Sinn :)

Bleibt jetzt nur noch die Frage zu klären, ob ich mit dem Beispiel-Spiel aus dem Buch oder direkt mit SFML Game Development weiter mache :)

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

6

20.07.2017, 16:40

Mach mit dem Beispiel-Spiel weiter.
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]

TigerClaw25

unregistriert

7

21.07.2017, 12:48

Bin schon dabei. Was ich als Anfänger aber schwierig finde, ist die Vorgehensweise. Man hat zwar den kompletten Code aber in der Realität würde ich eventuell ein Fenster erzeugen und danach erst eine klasse Framework erstellen, um alles dann zu initialisieren. Viele Dinge erscheinen zwar logisch,aber auch das einfache Spiel im Buch ist für Anfänger nicht einfach und nach dem Buch könnte ich das Spiel von selbst nicht nachprogrammieren. Auch die Art des Aufbaus oder welche Methoden in der Klasse timer oder Framework enthalten sein sollen, wuesste ich danach nicht sofort. Die Grundlagen zu verstehen ist eine Sache. Den Zusammenhang bei größeren Projekten herzustellen, etwas anderes. Ich habe bejm sdl Spiel das Gefühl, dass ich sozusagen von null anfange. Ok für das framework gibt es tutorials und im Buch ist das lediglich besser verpackt Dank Klassen. Zudem benötigt man das Ganze nur ein mal aber eben die komplette Logik nachzuvollziehen und durchzublicken, finde ich schwer. Eine Funktion nachvollziehen ist einfacher als sich durch Programm Code zu hangeln, der endlos lang ist

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

8

21.07.2017, 13:03


Bin schon dabei. Was ich als Anfänger aber schwierig finde, ist die Vorgehensweise. Man hat zwar den kompletten Code aber in der Realität würde ich eventuell ein Fenster erzeugen und danach erst eine klasse Framework erstellen, um alles dann zu initialisieren. Viele Dinge erscheinen zwar logisch,aber auch das einfache Spiel im Buch ist für Anfänger nicht einfach und nach dem Buch könnte ich das Spiel von selbst nicht nachprogrammieren. Auch die Art des Aufbaus oder welche Methoden in der Klasse timer oder Framework enthalten sein sollen, wuesste ich danach nicht sofort. Die Grundlagen zu verstehen ist eine Sache. Den Zusammenhang bei größeren Projekten herzustellen, etwas anderes. Ich habe bejm sdl Spiel das Gefühl, dass ich sozusagen von null anfange. Ok für das framework gibt es tutorials und im Buch ist das lediglich besser verpackt Dank Klassen. Zudem benötigt man das Ganze nur ein mal aber eben die komplette Logik nachzuvollziehen und durchzublicken, finde ich schwer. Eine Funktion nachvollziehen ist einfacher als sich durch Programm Code zu hangeln, der endlos lang ist

Das Projekt ist ja auch erst mal nur ein Beispiel. Deine eigenen Projekte müssen gar nicht so aufgebaut sein. Spiel einfach noch ein wenig mit dem Projekt rum und versuche dich dann mal an etwas eigenem. Dabei würde ich dann aber erst mal wirklich simpel starten. Pong ist für den Anfang eine gute Sache. Wenn das läuft kannst du dich mal an Breakout versuchen. Wie du deinen Code dabei aufbaust und strukturierst ist dann natürlich dir überlassen.
Man kann übrigens auch Spiele in für die Konsole schreiben. Beispiele sind Textadventures, Hangman, Mastermind oder Tic Tac Toe. Vielleicht versuchst du es auch erst mal mit so etwas.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

9

24.07.2017, 10:34

Bin schon dabei. Was ich als Anfänger aber schwierig finde, ist die Vorgehensweise. Man hat zwar den kompletten Code aber in der Realität würde ich eventuell ein Fenster erzeugen und danach erst eine klasse Framework erstellen, um alles dann zu initialisieren. Viele Dinge erscheinen zwar logisch,aber auch das einfache Spiel im Buch ist für Anfänger nicht einfach und nach dem Buch könnte ich das Spiel von selbst nicht nachprogrammieren. Auch die Art des Aufbaus oder welche Methoden in der Klasse timer oder Framework enthalten sein sollen, wuesste ich danach nicht sofort. Die Grundlagen zu verstehen ist eine Sache. Den Zusammenhang bei größeren Projekten herzustellen, etwas anderes. Ich habe bejm sdl Spiel das Gefühl, dass ich sozusagen von null anfange. Ok für das framework gibt es tutorials und im Buch ist das lediglich besser verpackt Dank Klassen. Zudem benötigt man das Ganze nur ein mal aber eben die komplette Logik nachzuvollziehen und durchzublicken, finde ich schwer. Eine Funktion nachvollziehen ist einfacher als sich durch Programm Code zu hangeln, der endlos lang ist


Ging mir am Anfang ähnlich, aber habe dann damals die Verbesserungsvorschläge oder Erweiterungsvorschläge aus dem Buch eingebaut und den bestehenden Code immer stückweise angepasst und erweitert. Irgendwann bekommt man schon ein Gefühl dafür, was wohin gehört. Danach kannst du ein eigenes kleines Spiel versuchen und sicher einige der Klassen aus dem Buch-Spiel oder zumindest das Grundgerüst recyclen.

TigerClaw25

unregistriert

10

24.07.2017, 11:06

Genau und vor allem wenn ich auf Anhieb programmieren würde, würde ich wahrscheinlich garnicht großartig überlegen ob statisch, global oder lokal oder ob ich bestimmte Techniken verwende. Wahrscheinlich würde ich dann mit einfachen if Bedingungen arbeiten, etc.. Na ja, eventuell kommt das alles nach und nach. Zumindest sind mir vielen Dinge immer klarer, auch wenn zwischen Grundlagen können und dann auch gezielt anzuwenden Welten liegen, und absolut nicht zu meinem Talent zählt

Werbeanzeige