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

24.03.2015, 16:10

7.8 Aufgabenstellung (Klassen, Konstruktoren etc.) Mehrere Unklarheiten

Hallo Leute! Ich bin jetzt im Buch bei der Aufgabenstellung zu den Klassen.
In dieser soll eine Klasse erstellt werden, die ein paar Membervariablen besitzt. 2 Konstruktoren soll es geben. (Einen für das Spieler-Raumschiff und eines für den Gegner)

Ich soll auf dem Heap zwei Instanzen der Klasse reservieren und am Ende mit einem Destruktor (der eine Meldung ausgibt) den Speicher wieder freigeben.
Hier mein Code, der auch funktioniert. Hab nur den Gegner wieder rausgelöscht, aufgrund der Übersicht.
Meine Fragen kommen nach dem Code.


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
#include <iostream>
using namespace std;


class cRaumschiff
{
private:
    int m_xPos, m_yPos;
    int Energie;
    int Speed;
public:
    cRaumschiff();
    cRaumschiff(int x, int y);
    ~cRaumschiff();
    void ZeigeDaten();

};



int main()
{
    
    
    int xPos = 0;
    int yPos = 0;


    
    cRaumschiff Spieler1;
    cRaumschiff *pSpieler = new cRaumschiff;
    
    Spieler1.ZeigeDaten();

    delete pSpieler;
    
    
    

    
    
    
    return 0;
}


/*//////////////////////////////// KONSTRUKTOR*/
cRaumschiff::cRaumschiff()
{
    cout << "Konstruktor aufgerufen!" << endl;
    int m_xPos = 0;
    int m_yPos = 0;
    int Energie = 1000;
    int Speed = 0;
}


/*///////////////////////////////////// DESTRUKTOR*/

cRaumschiff::~cRaumschiff()
{
    cout << "Destruktor wurde aufgerufen!" << endl;
}
/*//////////////////////////// DATEN ANZEIGEN*/
void cRaumschiff::ZeigeDaten()
{
    cout << "Energie:   " << Energie << endl;
    cout << "Geschwind: " << Speed << endl;
    cout << "x-Pos: " << m_xPos << endl;
    cout << "y-Pos: " << m_yPos << endl;
}



Frage 1:
Wieso muss ich dem Zeiger keine Adresse zuweisen mit dem kaufmännischen &?
Ich dachte, ein Zeiger muss immer auf eine Adresse zeigen! (siehe cRaumschiff *pSpieler = new cRaumschiff;)



Frage 2:

Wie man sieht, hab ich mir eine Instanz OHNE Speicherreservierung erstellt (cRaumschiff Spieler1;)
Dieser wird ja mit dem Standard-Konstruktor erstellt, welche die Variablen definiert.
Diese lasse ich mir einige Zeilen später mit "Spieler1.ZeigeDaten();" anzeigen.
Wenn ich das Programm aber starte, zeigt er mir für jede Variable den Wert "-858993560".
Diese müssten doch aber die Werte 0 besitzen bzw. 1000 für die Energie! Was mache ich falsch?

Frage 3:
Wie kann ich die ZeigeDaten()-Funktion für Instanzen anzeigen lassen, die ich auf dem Heap reserviert habe? *pSpieler.ZeigeDaten() sowieso pSpieler.ZeigeDaten() funktionieren nicht. Ich kann die Instanzen zwar erzeugen, aber mit deren Werten nicht weiterarbeiten? Was übersehe ich wieder?


---------------------------------------------------------------------------


Es tut mir leid, dass ich schon wieder ein Thema aufmache, weil ich nicht weiterkomme! Aber ich probiere wirklich viel selbstständig und frage erst, wenns wirklich gar nicht klappen will.
Ich hoffe, Ihr habt Verständnis und helft mir trotzdem!! :)


Liebe Grüße!

Lares

1x Contest-Sieger

  • Private Nachricht senden

2

24.03.2015, 17:16

Frage 1
Du brauchst kein &, weil du in

Quellcode

1
cRaumschiff *pSpieler = new cRaumschiff;

ein neuen Speicher für ein Raumschiff allokierst. Die Zuweisung = übergibt automatisch die entsprechende Speicheradresse. Dir wird in diesem Fall also sozusagen Arbeit abgenommen, weil Speicher allokieren ohne Zugriff auf die Adresse zu erhalten nicht so toll wäre.

Frage 2
Im Konstruktor weist du nicht den Klassenvariablen neue Werte zu, sondern erstellst Variablen. Schreibst du den Datentyp vor einem Variablennamen ist das eine Deklaration. Du musst also die ints entfernen.

Frage 3
Entweder

Quellcode

1
(*pSpieler).ZeigeDaten()

oder eleganter und gängiger

Quellcode

1
pSpieler->ZeigeDaten()

3

24.03.2015, 17:29

Wow! Super erklärt mit wenigen Worten. Vielen Dank! Zwar verstehe ich noch nicht warum ich " -> " benutzen muss, aber das wird sich im Laufe des Lernprozesses schon noch ergeben!
Vielen Dank :)

Lares

1x Contest-Sieger

  • Private Nachricht senden

4

24.03.2015, 17:39

Wow! Super erklärt mit wenigen Worten. Vielen Dank! Zwar verstehe ich noch nicht warum ich " -> " benutzen muss, aber das wird sich im Laufe des Lernprozesses schon noch ergeben!
Vielen Dank :)

Ist ne Eigenheit von C++, die auch einige professionelle Programmierer stört. Jemand kam halt mal auf den Gedanken, dass es sinnvoll sei zwischen Zugriffen auf Klasseninformationen über Pointern und normal zu unterscheiden.

birdfreeyahoo

Alter Hase

Beiträge: 756

Wohnort: Schorndorf

Beruf: Junior Software Engineer

  • Private Nachricht senden

5

24.03.2015, 17:43

-> benutzt du weil du ja erst den Zeiger dereferenzieren musst um die Funktion aufrufen zu können. Das machst du mit einem Stern normal, wie es Lares zeigt.
Allerdings ist die Schreibweise umständlich, vorallem weil das sehr oft verwendet wird, dass man einfach eine Abkürzung genommen hat. Der Pfeil ruft eine Funktion auf dem Objekt auf das der Pointer links vom Pfeil zeigt auf.

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

6

24.03.2015, 19:03

Es ist keine "Eigenheit" von C++.
Es ist schlicht und ergreifend so, dass in C++ nicht bei der Typdeklaration zwischen Referenz- und Wertetyp unterschieden wird.
Wenn du in C++ eine Klasse hast, kannst du die am Ort deiner Wahl direkt ablegen. Oder du kannst sie an einer anderen Stelle ablegen(zum Beispiel an irgendeiner beliebigen bisher unbenutzten Stelle, die man mit "new" bekommt) und nur darauf verweisen. Wenn man darauf zugreifen will, kann muss man erst mal die Stelle suchen, an die der Zeiger denn nun zeigt. Denn direkt da, ist das Objekt ja nicht. Man zeigt nur auf ein Objekt. Diese "Suche" macht man mit dem * und dem -> Operator.

Diese Freiheit, selbst zu entscheiden wo ein Objekt hinkommt, gibt es vielen Sprachen wie zum Beispiel Java/C# nicht. Dort ist jede Klasse hinter genau einem Zeiger. Deshalb muss man dort auch nicht unterscheiden. Ohne die Unterscheidung würden nur halt in C++ zum Beispiel Smart Pointer oder Doppelpointer nicht funktionieren.

Lares

1x Contest-Sieger

  • Private Nachricht senden

7

24.03.2015, 19:33

Es ist keine "Eigenheit" von C++.
Es ist schlicht und ergreifend so, dass in C++ nicht bei der Typdeklaration zwischen Referenz- und Wertetyp unterschieden wird.
Wenn du in C++ eine Klasse hast, kannst du die am Ort deiner Wahl direkt ablegen. Oder du kannst sie an einer anderen Stelle ablegen(zum Beispiel an irgendeiner beliebigen bisher unbenutzten Stelle, die man mit "new" bekommt) und nur darauf verweisen. Wenn man darauf zugreifen will, kann muss man erst mal die Stelle suchen, an die der Zeiger denn nun zeigt. Denn direkt da, ist das Objekt ja nicht. Man zeigt nur auf ein Objekt. Diese "Suche" macht man mit dem * und dem -> Operator.

Diese Freiheit, selbst zu entscheiden wo ein Objekt hinkommt, gibt es vielen Sprachen wie zum Beispiel Java/C# nicht. Dort ist jede Klasse hinter genau einem Zeiger. Deshalb muss man dort auch nicht unterscheiden. Ohne die Unterscheidung würden nur halt in C++ zum Beispiel Smart Pointer oder Doppelpointer nicht funktionieren.


Gut, dass du das ganze nochmal genauer erklärt hast, aber dir ist schon klar, dass deine Ausführung mir nicht wirklich widerspricht, oder? Wenn es an der Art liegt, wie C++ konzipiert wurde, ist es eine Eigenheit der Sprache.

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

8

24.03.2015, 19:59

Du hast es halt sehr negativ formuliert, als ob man das unbedingt hätte anders machen sollen und "Eigenheit" würde doch auch heißen, dass es ungewöhnlich ist.

Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

9

24.03.2015, 20:07

Naja man hätte es auch so lösen können, wie D es getan hat: automatische Dereferenzierung. In D ist (jedenfalls laut meinem letzten Stand) für alles der Punkt-Operator zuständig. Rufst du eine Methode an einem Zeiger auf, dann wird der Zeiger automatisch dereferenziert und du benötigst kein foo->bar oder (*foo).bar gedöhns. Ist manchmal echt schon nett gewesen. ;)
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

Lares

1x Contest-Sieger

  • Private Nachricht senden

10

24.03.2015, 20:22

Du hast es halt sehr negativ formuliert, als ob man das unbedingt hätte anders machen sollen und "Eigenheit" würde doch auch heißen, dass es ungewöhnlich ist.

Ich bin persönlich auch kein Freund dieser Unterscheidung, da es das Refactoring unnötig verlängert (gerade im Bezug auf Referenzen mit Pointern tauschen). Vllt hätte man es nicht anders lösen können, ohne Kompatibilität zu C oder andere wichtige Features der Sprache zu verlieren. Ich kenne mich nicht gut genug mit der Umsetzung der Sprache aus, um eine begründete Aussage darüber zu treffen. Schön wäre so eine Vereinheitlichung meiner Meinung nach trotzdem.

Werbeanzeige