mikrocontroller.net

Forum: PC-Programmierung Frage zu Destruktoren


Autor: Wasserfallkarzinom (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich habe mal eine Frage zu diesem C++, was ich grade zu lernen versuche.

Ich habe folgende Klasse


class Punkt
{
 private: int Koordinate [2];

 public: void set_x (int);
         void set_y (int);
         int get_x ();
         int get_y ();

 // Konstruktor
 Punkt (int K_x = 0, int K_y = 0);

 // Destructor
 ~Punkt ();

}

Also, jetzt hab ich meine Klasse Punkt definiert, mit einer privaten 
Variable Koordinaten für X/Y als Array und jeweils eine Funktion get und 
set, um die Variablen zu setzen und auszulesen.

Mit dem Konstruktor kann ich vorher Werte definieren, mit denen die 
Variablen der Klasse vorher initialisiert werden können. Als nächstes 
kann ich die einzelnen Funktionen nun beschreiben, was sie machen sollen

void Punkt :: set_x (int x_Koord)
{
 Koordinate [0] = x_Koord;
}

int Punkt :: get_x ()
{
 return Koordinate [0];
}

// Konstruktorfunktion
Punkt :: Punkt (int K_x, int K_y)
{
 Koordinate [0] = K_x;
 Koordinate [1] = K_y;
}

// Destructor
Punkt :: ~Punkt ()
{
 delete Koordinate;
}

Meine Frage dazu ist folgende ---> wann genau wird der Destructor 
aufgerufen? Der Konstruktor muss doch an der Stelle aufgerufen werden, 
wenn ich die Klasse Punkt in einer Funktion definiere also

Punkt Mittelpunkt;
und wenn ich dann schreibe

cout << Mittelpunkt.get_x;

dann müsste doch der Wert Null erscheinen, weil ich ihn beim Beschreiben 
der Klasse oben unter class Punkt ... mit Null gesetzt habe.

Aber wann wird der Destruktor aufgerufen? Wird er automatisch dann 
aufgerufen, wenn z.B. die Funktion, in der ich Mittelpunkt definiert 
hab, beendet wird?

Autor: ms (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da musst du dich in C++ selbst drum kümmern. Wenn du eben deinen 
Mittelpunkt nicht mehr brauchst.
"Modernere" Sprachen wie Java haben einen Garbage Kollektor und erkennen 
automatisch ob eine Instanz noch gebraucht wird.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
der Destruktoren wenn du den gültigkeitsbereich des Objektes verlässt.
{
   Punkt Mittelpunkt;
   cout << Mittelpunkt.get_x;
   cout << "test"
}  <-- jetzt wird der Destruktor von Punkt aufgerufen

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ms schrieb:
> Da musst du dich in C++ selbst drum kümmern.

nein muss man nicht, nur wenn man objekte mit new anlegt muss man sie 
wieder mit delete löschen.
Ich finde das verhalten von C++ sehr gut, im vergleich zu den Garbage 
Kollektor sprachen.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wasserfallkarzinom schrieb:
> Der Konstruktor muss doch an der Stelle aufgerufen werden,
> wenn ich die Klasse Punkt in einer Funktion definiere also

Wenn der Programmfluß an der Stelle vorbeikommt, an der
eine Variable von dem Typ definiert ist.

Also im Prinzip ja, mit der Einchränkung daß deine
Formulierung nicht stimmt, weil du nicht die Klasse nochmal
definierst, sondern ein Objekt davon, auch Instanz genannt.

> Aber wann wird der Destruktor aufgerufen? Wird er automatisch dann

Genau dann, wenn der Gültigkeitsbereich einer Variable verlassen
wird, also wenn die schließende geschweifte Klammer des
innersten Blocks  erreicht wird, der die Defintion der Variable
umgibt.


(Soweit gilt das für automatische Variablen.
Bei allokierten Objekten wird der Konstruktor aufgerufen
beim new, der Destruktor bei delete bzw. bei regulärem
Progerammende. Bei statischen lokalen Variablen der ctor
beim ersten Durchlauf der Definition, der dtor bei
Programmende. Bei globalen Variablen vor Eintritt in main()
bzw. bei Programmende.)

Steht in jedem besseren C++-Buch...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und zu guter letzt
// Destructor
Punkt :: ~Punkt ()
{
 delete Koordinate;
}


warum delete Koordinate?
Du hast den Member ja auch nicht mit new allokiert!

Solange du nichts mit new innerhalb der Klasse allokierst, brauchst du 
auch nichts deleten. Ganz im Gegenteil: So ist das ein schwerer Fehler!

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> der Destruktor bei delete bzw. bei regulärem Progerammende
das glaube ich nicht! Es gibt ja keine Runtime die objekte kennt. In C 
ist es nur ein zeiger und dort macht niemand beim programmende eine 
delete.
Zu jedem new muss man auch ein delete aufrufen(oder eine smartptr 
verwenden) sonst wird auch keine Destruktor aufgerufen.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter schrieb:
> Klaus Wachtler schrieb:
>> der Destruktor bei delete bzw. bei regulärem Progerammende
> das glaube ich nicht! Es gibt ja keine Runtime die objekte kennt. In C
> ist es nur ein zeiger und dort macht niemand beim programmende eine
> delete.
> Zu jedem new muss man auch ein delete aufrufen(oder eine smartptr
> verwenden) sonst wird auch keine Destruktor aufgerufen.

ups, sorry!
Du hast natürlich recht, bei new-Objekten wird auch bei Programmende
kein dtor aufgerufen.
Da war ich in Gedanken wohl schon bei den statischen :-(

Autor: Mark Brandis (markbrandis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zur Laufzeit belegten Speicher auf dem Stack löscht man natürlich nicht 
von Hand. Zur Laufzeit allokierten Speicher auf dem Heap sollte man 
tunlichst löschen, sofern man nicht ein nettes kleines Speicherleck 
haben will.

Autor: Wasserfallkarzinom (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich danke Euch für Eure Hilfe. Ich hab das Programm jetzt mal so 
eingetippt, hab auch im Konstruktor das new ergänzt, aber es kommen 
immer noch viele Fehlermeldungen :-(, die hab ich mal mit sternchen 
unten dranmakiert. Was mache ich denn noch falsch ?

// Versuchsprogramm

#include <iostream>

class Punkt
{
    private: int *Koordinate;

    public:  void set_x (int x);
             void set_y (int y);
             int get_x ();
             int get_y ();

    Punkt (int x = 0, int y = 0);
    ~ Punkt ();
}

void Punkt::set_x (int x)
{ ***
    Koordinate [0] = x ;
}

void Punkt :: set_y (int y)
{
    Koordinate [1] = y;
}

int Punkt :: get_x ()
{
    return Koordinate [0];
}

int Punkt :: get_y ()
{
    return Koordinate [1];
}

Punkt :: Punkt (int x, int y)
{
    Koordinate = new int [2];
    Koordinate [0] = x;
    Koordinate [1] = y;
}


Punkt :: ~Punkt ()
{
 delete Koordinate;
}

int main ()
{
    Punkt Mittelpunkt;

    return 0;
}

***
error: new types may not be defined in a return-typ
note: (perhaps a semicolon is missing after the definition of Punkt)
error two or more data types in declaratiopn of set_x
error ...

Autor: Mark .. (mork)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>note: (perhaps a semicolon is missing after the definition of Punkt)

Nach class Punkt { ... } gehört ein Semikolon hin.

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Manchmal frage ich mich, ob der Compiler die Fehlermeldungen erst 
vortanzen muss, damit die User sie auch mal beachten...

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
mach es lieber ohne das new im Konstruktor!.

Jezt hast du ein Problem wenn du das Objekt kopierst.
int main ()
{
    Punkt Mittelpunkt;

    Punkt2 Mittelpunkt = Punkt;

    return 0;
}

und schon stützt dein Programm ab, weil du den Zeiger 2mal freigeben 
willst. Wenn man zeiger in Objekten verwendet sollte man genau wissen 
mas man macht.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch wenn ich verstehe, dass es sich hier um ein Übungsbeispiel handelt, 
sollte man es trotzdem ansprechen:

+-----------------------------------------------------------+
|                                                           |
|     Allokiere nichts mit new, wenn du nicht musst!        |
|                                                           |
+-----------------------------------------------------------+

In deinem Beispiel musst du nicht. Mit
class Punkt
{
  public:
    Punkt (int x = 0, int y = 0);

    void set_x (int x);
    void set_y (int y);
    int get_x ();
    int get_y ();

  private:
    int Koordinate[2];
};

ist deine Klasse perfekt und du brauchst auch keinen Destruktor explizit 
schreiben.

Wenn du nämlich innerhalb der Klasse mittels new etwas allokierst, dann 
musst du dich auch um die 'Rule of 3' kümmern:

Wenn eine Klasse mindestens einen der 3
  * Destruktor
  * Copy Constructor
  * Zuweisungsoperator
hat, dann ist es sehr wahrscheinlich, dass alle 3 notwendig wären.

Deine Klasse hat einen Destruktor (aus gutem Grund) und sie müsste 
eigentlich auch einen von dir geschriebenen Copy Constructor und einen 
Zuweisungsoperator haben, um mit ihr fehlerfrei arbeiten zu können. Hat 
sie aber nicht. Wenn es daher bei der Verwendung deiner Klasse dazu 
kommt, dass eines der beiden benutzt wird, und sei es nur auf diese Art
int main()
{
  Punkt a;
  Punkt b;

  a = b;
}

dann hat deine Klasse mit der dynamischen Allokierung jetzt einen 
schweren Fehler gebaut, weil die vom Compiler generierte 
Zuweisungsoperation das Falsche macht.

PS: Das hier
Punkt :: ~Punkt ()
{
 delete Koordinate;
}

ist sowieso falsch.
Du allokierst mit einem Array-new
   Koordinate = new int[2];

also musst du auch ein Array-delete verwenden
   delete [] Koordinate;

Autor: Wasserfallkarzinom (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> PS: Das hier
> Punkt :: ~Punkt ()
> {
>  delete Koordinate;
> }

Ich hatte gedacht, da ich doch in dem Bereich class Punkt Koordinate als 
Zeiger definiert hab, kann ich das so schreiben ohne die Arrayklammer 
[], da doch das Dingen ein Pointer sein soll, oder hab ich das falsch 
gedacht?


Peter schrieb:
> int main ()
> {
>     Punkt Mittelpunkt;
>
>     Punkt2 Mittelpunkt = Punkt;
>
>     return 0;
> }

Ich verstehe dass jetzt leider auch noch nicht, warum wird erst 
geschrieben Punkt Mittelpunkt, und dann Punkt2 Mittelpunkt = Punkt, was 
passiert denn dann? Dass heisst doch irgendwie Mittelpunkt sei eine 
Variable vom Typ Punkt2 mit dem Inhalt Punkt, aber es gibt doch in dem 
Programm bisher kein Punkt2?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wasserfallkarzinom schrieb:
> Karl heinz Buchegger schrieb:
>> PS: Das hier
>> Punkt :: ~Punkt ()
>> {
>>  delete Koordinate;
>> }
>
> Ich hatte gedacht, da ich doch in dem Bereich class Punkt Koordinate als
> Zeiger definiert hab, kann ich das so schreiben ohne die Arrayklammer
> [], da doch das Dingen ein Pointer sein soll, oder hab ich das falsch
> gedacht?

Die Sache ist eigentlich ganz einfach und eindeutig

Benutzt du

   new

dann lautet das Gegenstück dazu

   delete

benutzt du

   new []

dann lautet das Gegenstück dazu

   delete []

Zusammengefasst:
   new      -   delete
   new []   -   delete []

Ich wünschte, alle Regeln in C++ wären so dermassen eindeutig und klar 
und völlig ohne Ausnahmen :-)
(Das einzige was ich mir noch mehr wünschen würde wäre, dass es bei 
delete keine 2 Formen geben müsste. Aber aus Gründen, die hier nicht 
weiter diskutiert werden sollen, ist das nun mal so)

Wie allokierst du?
...
    Koordinate = new int [2];
...
Aha. mit einem new[]
Also muss es
   delete [] Koordinate;
lauten.

Und nein: Das ist kein Kavaliersdelikt!

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Versuch es doch mal bitte mit einem C++-Buch.

Es ist relativ ineffizient, jedem alles extra erklären zu müssen,
was schon in 531 Büchern steht und dort nur gelesen werden muss.
Hier müsstest du es doch auch lesen...

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PC: ich meinte jetzt NICHT KHB damit :-)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wasserfallkarzinom schrieb:

> Peter schrieb:
>> int main ()
>> {
>>     Punkt Mittelpunkt;
>>
>>     Punkt2 Mittelpunkt = Punkt;
>>
>>     return 0;
>> }
>
> Ich verstehe dass jetzt leider auch noch nicht

Peter hat gepatzt :-)

er wollte eigentlich das hier schreiben
int main ()
{
  Punkt Mittelpunkt;
  Punkt Mittelpunkt2 = Mittelpunkt;

  return 0;
}

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht wollte er aber auch das schreiben:
int main ()
{
  Punkt Mittelpunkt;
  Punkt Mittelpunkt2;
  Mittelpunkt2 = Mittelpunkt;

  return 0;
}

Wer weiß?

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Karl heinz Buchegger &&  @Klaus Wachtler

Ich sehe wir verstehen uns, ja das habe ich gemeint.

Danke

Autor: Wasserfallkarzinom (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ach so, du meinst das jetzt bezogen auf die klasse, die du mir so 
geschickt hast, weil du geschrieben hast


private:
  int Koordinate [2];, darum folglich delete [] Koordinate.

Und wenn ich geschrieben hab
  int *Koordinate;
dann hätte ich nur schreiben müssen
 delete Koordinate, oder? weil ich das bei mir ja noch mit int 
*Koordinate hätte stehen lassen müssen.

Ich hab mal noch eine andere Frage. Wenn ich jetzt folgendes mache: Im 
Class-Bereich:

private: int *Koordinate;

und dann im Konstruktor:

Koordinate = new int [2];

dann müsste das doch auch gleich sein, oder? und dann kann ich doch 
schreiben im Destruktor:

delete Koordinate?

Ich bin da immer noch ein bißchen durcheinander, sorry. Ich versuche das 
erstmal, es zu verstehen. Ich verstehe z.B. auch noch nicht, warum man 
im Class-Bereich bei der Definition schreibt:


public: void set_x (int);

also, man sagt also damit jetzt dem Compiler, set_x kann eine Variable 
vom Typ int annehmen, oder?

wenn ich jetzt folgendes machen würde:

public: void set_x (int);
        void set_x (float);

kann ich dann später bei den Funktionen, wo ich schreibe, was denn die 
Funktion set_x machen soll, dann auch zwei FUnktionen schreiben

Punkt :: set_x (int x) {...};
Punkt :: set_x (float x) {...};

und er nimmt dann einfach bei einem Float die zweite Funktion und bei 
int die erste Funktion, ist dass dann auch so?

Sind denn eigentlich diese beiden Dinger identisch?

*(Koordinate+1) = Koordinate [1], also dass ich bei Zuweisungen sowohl 
schreiben kann

*(Koordinate+1) = y und Koordinate[1] = y; wäre dass identisch? Wenn ja, 
wann nehme ich die Zuweisung mit dem Pointer und wann mit dem Arrayfeld?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wasserfallkarzinom schrieb:
> ach so, du meinst das jetzt bezogen auf die klasse, die du mir so
> geschickt hast,

nein

> weil du geschrieben hast
>
>
> private:
>   int Koordinate [2];, darum folglich delete [] Koordinate.

in dem Fall braucht es überhaupt kein delete

>
> Und wenn ich geschrieben hab
>   int *Koordinate;
> dann hätte ich nur schreiben müssen
>  delete Koordinate, oder?

Ist das wirklich so schwer?

Du schreibst.
Punkt :: Punkt (int x, int y)
{
    Koordinate = new int [2];
    Koordinate [0] = x;
    Koordinate [1] = y;
}

d.h. du allokierst ein Array mittles new[]

also musst du beim Freigeben auch die Schreibweise für Arrays benutzen
Punkt :: ~Punkt ()
{
 delete [] Koordinate;
}

Das ist doch wirklich nicht schwer!


> weil ich das bei mir ja noch mit int
> *Koordinate hätte stehen lassen müssen.

Der Pointer hat damit nichts zu tun.
Es geht darum worauf der Pointer zeigt:
ein einzelnes Objekt oder ein Array von Objekten

Autor: Wasserfallkarzinom (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich möchte Euch sehr herzlich für Eure Erklärungen bedanken. Natürlich 
habe ich auch ein Buch und auch ein PDF-Script, anhand dessen versuche 
ich, dass ja auch so ein bißchen zu kapieren, aber manchmal verstehe ich 
das noch nicht, was da auch in dem Buch bzw. Script drinnen steht, dann 
ist es sehr hilfreich, wenn man eine Bestätigung bekommt, ob man etwas 
richtig verstanden hat, wie z.B. meine Frage eben, ob diese Sache mit 
den zwei Sachen einmal gleich ist und so und das mit dem Semikolon 
hinter der Klasse, die ich bei der einen Fehlermeldung einfach nicht 
erkannt hab, dass hab ich halt einfach so nicht gesehen, weil ich da 
noch recht frisch bin, für Euch ist das wahrscheinlich standardmaessig 
so, dass ihr hinter einem Ende einer Klasse automatisch ein Semikolon 
setzt und so einen Fehler sofort seht, ich war eben als halt bei der 
Funktion darunter, weil dort der Compiler den Fehler angezeigt hat, es 
aber dann auf die vorige Klasse gemeint hatte und ich hätte 
wahrscheinlich noch 2 Stunden davor gehangen und wäre nicht 
weitergekommen mit dem Compilieren, wenn Ihr mir nicht geholfen hättet .

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wasserfallkarzinom schrieb:

> public: void set_x (int);
>
> also, man sagt also damit jetzt dem Compiler, set_x kann eine Variable
> vom Typ int annehmen, oder?

Ja.
set_x ist eine Funktion, die einen int als Argument annimmt und nichts 
zurückliefert.

Aber diese Schreibweise solltest du dir gleich gar nicht angewöhnen. Gib 
dem Argument gleich einen Namen, damit derjenige, der die 
Klassenbeschreibung liest, auch weiß was Sache ist.

Oder kennst du dich aus, bei folgendem Funktionskopf

   double CalculateNettoPreis( double, double );

Was ist das erste Argument, was ist das zweite Argument?

Im Vergleich dazu

    double  CalculateNettoPres( double BruttoPreis, double Steuersatz );

Welche der beiden Formen ist klarer in der Benutzung?

> wenn ich jetzt folgendes machen würde:
>
> public: void set_x (int);
>         void set_x (float);
>
> kann ich dann später bei den Funktionen, wo ich schreibe, was denn die
> Funktion set_x machen soll, dann auch zwei FUnktionen schreiben
>
> Punkt :: set_x (int x) {...};
> Punkt :: set_x (float x) {...};

du kannst nicht nur, du musst sogar. Das erste ist innerhalb der 
Klassendeklaration. In der ist alles zusammengefasst, was ein Benutzer 
der Klasse wissen muss. Da drinnen ist quasi das Versprechen einer 
Klasse an die Aussenwelt "Das alles kann ich". Die Aussenwelt muss nur 
wissen, dass es 2 Funktionen set_x gibt. Aber nur das Versprechen "Es 
gibt da 2 Funktionen" ist natürlich zu wenig. Die beiden Funktionen 
müssen auch existieren!

> und er nimmt dann einfach bei einem Float die zweite Funktion und bei
> int die erste Funktion, ist dass dann auch so?

Ja, das ist so

> Sind denn eigentlich diese beiden Dinger identisch?
>
> *(Koordinate+1) = Koordinate [1], also dass ich bei Zuweisungen sowohl
> schreiben kann

Ja. sind identisch.
Aber tu dir selbst einen Gefallen, Benutze nicht die erste Schreibweise, 
solange du nicht einen guten Grund dafür hast (und nein, dass Koordinate 
ein Pointer ist, ist kein guter Grund)

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wasserfallkarzinom schrieb:
> *(Koordinate+1) = y und Koordinate[1] = y; wäre dass identisch? Wenn ja,
> wann nehme ich die Zuweisung mit dem Pointer und wann mit dem Arrayfeld?

Die Variante mit Feld nimmt man, wenn es sich um ein Feld handelt,
die andere Variante eher, wenn es kein Feld ist, sondern nur ein
Zeiger mit irgendeiner Rechnerei.
Dem Compiler ist es egal, aber mit der Schreibweise kann man
ausdrücken, was man machen will - für einen menschlichen Leser,

Die dritte Variante wäre 1[Koordinate] = y und ebenfalls
gleichwertig.
Die nimmt man aber nie, außer um andere zu ärgern oder um zu
zeigen, was man alles für tolle Sachen beherrscht.

Autor: Wasserfallkarzinom (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Aber diese Schreibweise solltest du dir gleich gar nicht angewöhnen. Gib
> dem Argument gleich einen Namen, damit derjenige, der die
> Klassenbeschreibung liest, auch weiß was Sache ist.
>
> Oder kennst du dich aus, bei folgendem Funktionskopf
>
>    double CalculateNettoPreis( double, double );
>
> Was ist das erste Argument, was ist das zweite Argument?
>
> Im Vergleich dazu
>
>     double  CalculateNettoPres( double BruttoPreis, double Steuersatz );
>
> Welche der beiden Formen ist klarer in der Benutzung?



Naja, stimmt, die zweite Variante ist die bessere, weil man dann sieht, 
dass ein Double-Wert zurückgeliefert werden kann und welche beiden 
Argumente übergeben werden. Kann ich denn bei der Deklaration die 
Anmerkungen BruttoPreis und Steuersatz als Kommentare betrachten, oder 
muss ich dann auch bei dem Programmteil dann, wo ich drinnen stehen hab

XYZ :: CalculateNettoPreis (double BruttoPreis, ...)
oder kann ich dann auch sowas reinschreiben
XYZ :: CalculateNettoPreis (double PreisBrutto, ...)

Ich habe jetzt an dem Programm von mir noch ein bißchen rumprobiert und 
ich hab einfach mal ausprobiert, wenn ich dann verschiedene Namen hab im 
Class-Bereich und in dem Methodendefinitionsbereich, wo ich sage, was 
die Funktionen eigentlich machen sollen:

// Versuchsprogramm

#include <iostream>

class Punkt
{
    private: int *Koordinate;

    public:  void set_x (int x);
             void set_y (int y);
             void ausgeben ();
             int get_x ();
             int get_y ();

    Punkt (int x = 10, int y = 0);
    ~Punkt ();
};

void Punkt :: ausgeben ()
{
    std::cout << "\n X_Koord: " << get_x () << " Y_Koord: " << get_y ();
}

void Punkt :: set_x (int x)
{
    Koordinate [0] = x ;
}

void Punkt :: set_y (int y)
{
    Koordinate [1] = y;
}

int Punkt :: get_x ()
{
    return *(Koordinate);
}

int Punkt :: get_y ()
{
    return *(Koordinate+1);
}

Punkt :: Punkt (int xd, int y)
{
    Koordinate = new int [2];
    *(Koordinate) = xd;
    *(Koordinate+1) = y;
}


Punkt :: ~Punkt ()
{
    delete Koordinate;
    std::cout << "Im Destruktor ";
}

int main ()
{
    Punkt Mittelpunkt;
    std::cout << " \n Wert: " << Mittelpunkt.get_x ();
    std::cout << "\n";

    Mittelpunkt.ausgeben ();

    Mittelpunkt.set_x (200);
    Mittelpunkt.set_y (300);

    Mittelpunkt.ausgeben ();

    return 0;
}

Karl heinz Buchegger schrieb:
>> Sind denn eigentlich diese beiden Dinger identisch?
>>
>> *(Koordinate+1) = Koordinate [1], also dass ich bei Zuweisungen sowohl
>> schreiben kann
>
> Ja. sind identisch.
> Aber tu dir selbst einen Gefallen, Benutze nicht die erste Schreibweise,
> solange du nicht einen guten Grund dafür hast

Du schreibst mir jetzt, ich soll die erste Variante
*(Koordinate+1) nur bei einem guten Grund verwenden, was ist denn ein 
guter Grund bzw. was ist jetzt daran schlechter als an Koordinate [1]? 
Oder ist das auch eher nur der Überschtlichkeit halber, weil man im 
zweiten Fall gleich sieht, dass Koordinate ein Array ist?

Autor: Hannes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wasserfallkarzinom schrieb:
> Punkt :: Punkt (int xd, int y)
> {
>     Koordinate = new int [2];
>     *(Koordinate) = xd;
>     *(Koordinate+1) = y;
> }

Das ist so total falsch! Du musst Koordinate = new... ersetzen durch

malloc (Koordinate,sizeof(int[2]));

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
???
Wenigstens meckert das der Compiler dann auch an.

Trau keinem Gast...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wasserfallkarzinom schrieb:

> Naja, stimmt, die zweite Variante ist die bessere, weil man dann sieht,
> dass ein Double-Wert zurückgeliefert werden kann und welche beiden
> Argumente übergeben werden. Kann ich denn bei der Deklaration die
> Anmerkungen BruttoPreis und Steuersatz als Kommentare betrachten,

LOL.
Eigenartige Ausdrucksweise, aber ich versteh was du meinst.

Ja, die kannst du im Grunde (in diesem Fall) als Kommentare betrachten. 
An der Stelle der Klassendekleration interessiert sich der Compiler nur 
für den Datentyp.

> XYZ :: CalculateNettoPreis (double BruttoPreis, ...)
> oder kann ich dann auch sowas reinschreiben
> XYZ :: CalculateNettoPreis (double PreisBrutto, ...)

Kannst du. Die Argumentnamen müssen nicht übereinstimmen.
Allerdings: Es ist keine so gute Idee, da schlampig zu sein :-)

> *(Koordinate+1) nur bei einem guten Grund verwenden, was ist denn ein
> guter Grund

Bei dir nicht.
Bei dir ist ganz klar, dass Koordinate ein Pointer auf ein Array ist. 
Also benutz auch die Array-Syntax. C (und mit ihm C++) hat ein paar 
Sonderregeln eingeführt, damit genau das möglich ist.

Deine Sichtweise der Dinge soll sein: Hinter Koordinaten steht ein 
Array, also nehm ich auch Array Syntax, weil sie sich dafür natürlich 
anbietet.

Die andere, die Pointer-Variante, ist gleichwertig und ist in C++ weit 
weniger gebräuchlich als in C. Eigentlich so gut wie gar nicht, weil die 
Dinge in C++ meistens sehr viel strukturierter gemacht werden. Auch wird 
in C++ sehr viel weniger mit Pointern gearbeitet als in C. C++ hat hier 
einfach bessere Möglichkeiten.

> bzw. was ist jetzt daran schlechter als an Koordinate [1]?

Es verschleiert.
Oberste Maxime soll immer sein: Code soll für Menschen lesbar sein.
Wenn du ein Array hast, dann ist es das natürlichste von der Welt, dass 
Koordinate[0] das erste Array Element ergibt und Koordinate[1] das 
nächste.

Autor: Wasserfallkarzinom (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich danke Euch allen, dass ihr mir so viel geholfen habt, mir das 
Kapieren des Programmierzeugs ein bißchen verständlicher zu machen :-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.