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

27.07.2017, 13:54

Überladen von Operatoren

Ich habe ein wenig mit den überladenen Operatoren experimentiert, da in dem Buch nur mit welchen ohne Rückgabetyp gearbeitet worden ist.

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
#include <iostream>

using namespace std;
class CVektor3D {
public:
    CVektor3D(float x, float y, float z);

    CVektor3D operator+=(const CVektor3D &rhs)
    {
        m_x+=rhs.m_x;
        m_y+=rhs.m_y;
        m_z+=rhs.m_z;
        return  CVektor3D(m_x,m_y, m_z);
    }
    void ZeigeWerte();
    ~CVektor3D(){cout << "Destruktor" << endl;}

private:
    float m_x, m_y, m_z;
};

CVektor3D::CVektor3D(float x, float y, float z)
{
    m_x = x;
    m_y = y;
    m_z = z;
    cout << "Konstruktor" << endl;
}

void CVektor3D::ZeigeWerte()
{
        cout << "x " << m_x << endl;
        cout << "y " << m_y << endl;
        cout << "z " << m_z << endl;
}

int main ()
{
    
    CVektor3D Vektor1(1,2,3);
    CVektor3D Vektor2 (1,2,3);

    Vektor1+=Vektor2;
    Vektor1.ZeigeWerte();

    system ("Pause");
    return 0;
}

Der Code ruft insgesamt drei Konstruktoren auf. Je einen für die beiden Instanzen und wahrscheinlich ein dritter Kopierkonstruktor ausgelöst durch das "return" in der operator-Funktion. Der Destruktor wird jedoch nur 1x aufgerufen. Warum ist das so?

C-/C++-Quelltext

1
2
3
4
5
6
7
8
    CVektor3D operator+=(const CVektor3D &rhs)
    {
        CVektor3D temp(*this);
        m_x+=rhs.m_x;
        m_y+=rhs.m_y;
        m_z+=rhs.m_z;
        return  temp;
    }

Hier werden zwei Konstruktoren und zwei Destruktoren aufgerufen. Das leuchtet mir ein. Durch den "this" wird keine lokale Instanz erstellt, sondern vielmehr die Adresse kopiert, wenn ich das richtig verstehe. Stehe irgendwie auf dem Schlauch ...

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

2

27.07.2017, 14:11

Der Destruktor wird jedoch nur 1x aufgerufen. Warum ist das so?

Garantiert nicht!
Die übrigen Aufrufe erfolgen erst beim Verlassen der main-Funktion, nach deinem system("Pause");, so dass du die Ausgabe nicht siehst. Das system("Pause"); solltest du dir sowieso abgewöhnen. Brauchst du eigentlich auch gar nicht. Visual Studio baut doch automatisch so eine "Drücken Sie eine Taste ..."-Aufforderung ein. Zumindest wenn du das Programm mit Strg+F5 startest.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
CVektor3D operator+=(const CVektor3D &rhs)
{
    CVektor3D temp(*this);
    m_x+=rhs.m_x;
    m_y+=rhs.m_y;
    m_z+=rhs.m_z;
    return  temp;
}

Diese Implementierung ist gar nicht gut! Der Operator += sollte nicht eine Kopie des alten Objektzustands zurückliefern, sondern per Konvention das aktuelle Objekt verändern und eine Referenz darauf zurückliefern. Wenn du int i = 0; schreibst und dann std::cout << (i += 42), dann wird ja auch 42 ausgegeben und nicht 0. Richtig wäre also:

C-/C++-Quelltext

1
2
3
4
5
6
7
CVektor3D& operator+=(const CVektor3D &rhs)
{
    m_x+=rhs.m_x;
    m_y+=rhs.m_y;
    m_z+=rhs.m_z;
    return *this;
}

TigerClaw25

unregistriert

3

27.07.2017, 14:37

Ok, so mache ich das. Eine Frage noch. Wozu überhaupt return bzw. wo wirkt es sich genau aus? Die Werte werden innerhalb der "*.operator"-Funktion bereits durch "+=" geändert. Das heißt, mit einem void wäre es auch getan und ich könnte die Membervariablen m_x, m_y und m_z auch ohne Rückgabewert aufrufen.

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

4

27.07.2017, 14:43

Ok, so mache ich das. Eine Frage noch. Wozu überhaupt return bzw. wo wirkt es sich genau aus?

Das wirkt sich erst mal gar nicht aus. Du brauchst auch nicht unbedingt einen Rückgabetyp. Per Konvention macht man das aber so. Dadurch kannst du verschiedene Operatoren verketten. Der Code den David gepostet hat funktioniert zum Beispiel nur weil du das Objekt selbst zurück gibst. Die Operatoren << und >> von Streams arbeiten übrigens genau so. Ansonsten könntest du Ausgaben nicht verketten.
„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.“

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

5

27.07.2017, 17:25

Ok, so mache ich das. Eine Frage noch. Wozu überhaupt return bzw. wo wirkt es sich genau aus?

Wie gesagt, mit den eingebauten Typen wie int etc. geht das ja auch:

int i = 0;
std::cout << (i += 42) << std::endl;

Gibt 42 aus.
Oder für das Beispiel deiner Klasse:

CVektor3D v(1, 2, 3);
(v += CVektor3D(1, 1, 1)).ZeigeWerte();

Das ginge nicht, wenn der Operator += nichts zurückgeben würde.
Auch sowas geht:

(v += CVektor3D(1, 1, 1)) += CVektor3D(2, 2, 2);

TigerClaw25

unregistriert

6

28.07.2017, 07:19

Im Buch habe ich mehrere Beispiele gesehen, bei denen kein INstanzname existiert. Genau so wie in meinem Beispiel oben mit "return CVektor3D(m_x,m_y, m_z);". Man gibt nur die Klassenbezeichnung an ohne eine Instanz. Warum funktioniert soetwas überhaupt? Mit return gebe ich eine Klasseninstanz zurück bzw. rufe den Kopierkonstruktor auf und kann somit die Werte x,y und z an die Klasse zurückgeben, um das Ergebnis der Addition zu erhalten.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

7

28.07.2017, 07:21

Warum funktioniert soetwas überhaupt?
Weil das der Aufruf eines Konstruktors ist und somit eine Instanz erzeugt wird, die dann direkt zurückgegeben wird.
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]

Werbeanzeige