Klassen "verbinden" - erledigt!

  • C++

  • Alpha Blondy
  • 2306 Aufrufe 17 Antworten

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Klassen "verbinden" - erledigt!

    Hey Freesoft-Board!

    Ich glaub, meine Frage ist ziemlich simpel, aber ich hab auch nach langem Googeln keine Antwort bekommen:

    Wie kann ich in C++ Klassen "verbinden" (also wie in Java mit Referenzattributen)?
    Ich will also ein Objekt einer Klasse in einer anderen Klasse deklarieren!

    Wer kann mir helfen?

    Danke im Voraus,

    Alpha Blondy

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von Alpha Blondy ()

  • Hm... weiss nicht genau, was du meinst.

    Kannst du mal einen Beispielcode in Java hier posten, der nach C++ geaendert werden soll?

    Ansonsten, um dich woertlich zu nehmen:

    Alpha Blondy schrieb:

    Ich will also ein Objekt einer Klasse in einer anderen Klasse deklarieren!

    Quellcode

    1. class A { }
    2. class B {
    3. [B]A bla;[/B]
    4. }



    Allerdings:
    (also wie in Java mit Referenzattributen)

    Referenzen werden in C++ durch Pointer gemacht.

    Quellcode

    1. class A { }
    2. class B {
    3. [B]A *bla;[/B]
    4. }
    Wo ist der Discord Server

    Dieser Beitrag wurde bereits 8 mal editiert, zuletzt von Skyte ()


  • class A
    { };

    class B
    {
    A *bla;
    };


    Ja, ja, das ist genau das, was ich meine! :)

    D.h. ich kann nicht wie in Java einfach Folgendes schreiben:

    Quellcode

    1. class A
    2. { };
    3. class B
    4. {
    5. A bla;
    6. };


    sondern ich muss das dann mit einem Zeiger (Pointer) lösen...

    Kannst du mir das bitte noch genauer erklären?

    Thx

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Alpha Blondy ()

  • Alpha Blondy schrieb:

    D.h. ich kann nicht wie in Java einfach Folgendes schreiben

    Du kannst es schon schreiben, es hat nur ne andere Bedeutung.

    Wenn du schreibst:

    Quellcode

    1. A bla;

    Dann wird fuer dieses bla Speicher allokiert und es hat genau die Groesse von so einem A.

    Wenn du aber schreibst:

    Quellcode

    1. A *bla;

    Dann ist die Variable bla nur ein Pointer, das heisst in bla wird kein A gespeichert, sondern eine einfache Zahl, naemlich die Adresse von einem A, auf das bla zeigt.

    Also wenn du sowas schreibst:

    Quellcode

    1. A blubb(parameter1, paramete2, ...);
    2. A bla; // ruft default Konstruktor auf
    3. bla = blubb;
    4. bla = NULL;


    Dann hast du zwei von einander unabhaengige Objekte bla und blubb.
    Zuerst wurde blubb sozusagen in bla reinkopiert und dann wurde bla mit NULL ueberschrieben. blubb wurde nicht veraendert.

    Wenn du aber schreibst:

    Quellcode

    1. A blubb;
    2. A *bla;
    3. bla = &blubb;
    4. *bla = NULL;

    Dann hast du nur ein A Objekt, naemlich dieses blubb. bla zeigt nur darauf und jetzt ist es wie in Java.
    Wenn also bla (also eigentlich *bla) mit NULL ueberschrieben wird, dann auch blubb.

    Was anderes waere bla = NULL, dann wird einfach die Referenz auf NULL gesetzt und mit blubb passiert nix.

    Steht aber auch alles im Internet. Google einfach nach C++ Tutorial Pointer.

    PS: Aequivalent zum letzten Code muesste auch das hier sein:

    Quellcode

    1. A blubb;
    2. A &bla = blubb;
    3. bla = NULL;

    de.wikibooks.org/wiki/C%2B%2B-…ere_Grundelemente/_Zeiger
    de.wikibooks.org/wiki/C%2B%2B-…Grundelemente/_Referenzen
    Wo ist der Discord Server

    Dieser Beitrag wurde bereits 13 mal editiert, zuletzt von Skyte () aus folgendem Grund: Code war falsch

  • Jetzt muss aber (für Java-Programmierer) noch folgendes kommen.
    Wenn man die Zeile "A blubb = new A();" schreibt, dann muss irgendwo auch ein
    "delete blubb;" stehen. Sonst bleibt das Teil bis in alle Ewigkeit im Speicher.
    Das kennt man aus C# und Java nicht, da sich dort die Garbage Collection drum kümmert (was ich übrigens sehr schätze).
    Es sei denn, man verwendet in c++ "auto_ptr".
    Nachzlesen bei: Kompf.de - Zeigerautomatik mit auto_ptr
    Es ist besser zu schweigen und für einen Narren gehalten zu werden, als zu reden und damit alle Zweifel zu beseitigen ...
  • Okay, danke.

    Ich hab jetzt verstanden, was ihr erklärt habt, aber ich bin mir noch nicht ganz sicher, ob wir über das gleiche sprechen bzw. wie ich das jetzt anwenden kann...

    Ich geb euch mal ein Beispiel:


    Ich hab eine Klasse "Spielfeld" und eine Klasse "Koordinate", und ich will nun zwischen diesen eine 1:n - Beziehung erstellen, sodass dann das Spielfeld aus n Koordinaten besteht (die Koordinaten also Referenzattribute der Klasse Spielfeld sind) - wie muss ich dann diesen Code erweitern?


    Quellcode

    1. class Koordinate
    2. {
    3. public:
    4. Koordinate();
    5. int x;
    6. int y;
    7. };
    8. class Spielfeld
    9. {
    10. public:
    11. Spielfeld();
    12. const int Hoehe;
    13. const int Breite;
    14. };
    Alles anzeigen
  • Hm... mit Koordinaten find ich bloed, da die sich sowieso schon aus Hoehe und Breite ergeben. Ich hab mal mit Feldern und Farben gemacht.
    Also 1 Spielfeld hat n Felder und die Felder haben jetzt mal ne Farbe.

    C-Quellcode

    1. #include <string>
    2. #include <iostream>
    3. using namespace std;
    4. class Feld {
    5. private:
    6. string color;
    7. public:
    8. Feld()
    9. :color("white")
    10. { }
    11. Feld(string p_color)
    12. : color(p_color)
    13. { }
    14. ~Feld() { }
    15. string getColor() {
    16. return color;
    17. }
    18. void setColor(string p_color) {
    19. color = p_color;
    20. }
    21. };
    22. class Spielfeld {
    23. private:
    24. int height;
    25. int width;
    26. Feld **field;
    27. public:
    28. Spielfeld() { }
    29. Spielfeld(int p_height, int p_width)
    30. : height(p_height),width(p_width)
    31. {
    32. int i;
    33. field = new Feld*[p_height];
    34. for (i = 0; i < p_height; i++) {
    35. field[i] = new Feld[p_width];
    36. }
    37. }
    38. ~Spielfeld() {
    39. int i;
    40. for (i = 0; i < height; i++) {
    41. delete[] field[i];
    42. }
    43. delete[] field;
    44. }
    45. Feld* getField(int p_height, int p_width) {
    46. return &field[p_height][p_width];
    47. }
    48. };
    49. int main() {
    50. Spielfeld spielfeld(3,5); // muss ich nicht mit delete loeschen
    51. Feld *feld;
    52. feld = spielfeld.getField(0,2);
    53. (*feld).setColor("blue");
    54. cout << (*spielfeld.getField(0,2)).getColor() << endl;
    55. Spielfeld *spielfeld2;
    56. spielfeld2 = new Spielfeld(1,1); // Instanz auf dem Heap, muss ich selber loeschen
    57. feld = (*spielfeld2).getField(0,0);
    58. cout << (*feld).getColor() << endl;
    59. delete spielfeld2;
    60. return 0;
    61. }
    Alles anzeigen


    Ist der Code klar oder soll ich erklaeren?

    PS:

    Quellcode

    1. Feld **field;

    bedeutet im Prinzip das Gleiche wie

    Quellcode

    1. Feld[][] field;
    Wo ist der Discord Server

    Dieser Beitrag wurde bereits 22 mal editiert, zuletzt von Skyte ()

  • Das heißt, du hast die Klassen durch [...] verbunden, oder?

    Ja.

    Die beiden Sterne bedeuten erstmal nur, dass es ein Pointer auf einen Pointer ist. Man kann aber Pointer wie Arrays behandeln.
    Sinngemaess heisst die Zeile also (in diesem Fall): field ist ein zweidimensionales Array von Feldern.
    D.h. wenn ich schreibe:

    Quellcode

    1. int* a = Adresse von irgendwas

    Dann kann ich mit *a auf irgendwas zugreifen.
    Genauso geht es aber auch mit a[0]. In eckigen Klammern steht einfach nur das Offset. Ich kann auch a[1] schreiben und greife dann auf die Adresse zu, wo die Adresse von a plus 1 hinzeigt.

    Und warum ist mein Beispiel nicht sinnvoll?

    Naja, du hast ein Spielfeld mit Hoehe mal Breite Koordinaten und die Koordinaten waeren ja dann wie mein Feld Array.
    Also z.B. so:

    Quellcode

    1. Koordinaten **cors;


    Wenn ich jetzt aber auf cors[3][7] zugreife, dann weiss ich schon vorher, dass cors[3][7].x = 3 und cors[3][7].y = 7.
    Von daher machts keinen Sinn, find ich. Es sei denn, ich habs falsch verstanden.
    Wo ist der Discord Server

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von Skyte ()

  • Wenn ich jetzt aber auf cors[3][7] zugreife, dann weiss ich schon vorher, dass cors[3][7].x = 3 und cors[3][7].y = 7.
    Von daher machts keinen Sinn, find ich.


    OK, hast Recht ;)
    Aber mal angenommen, ich will "Schiffe versenken" programmieren; da besteht doch das Spielfeld aus nur einem Feld (dafür aber aus vielen Koordinaten)!

    Ansonsten:
    habe ich das jetzt richtig verstanden?

    Quellcode

    1. class A
    2. {
    3. A();
    4. int bla;
    5. };
    6. class B
    7. {
    8. B();
    9. int blubb;
    10. A *refAttribut;
    11. };
    Alles anzeigen

    refAttribut zeigt jetzt quasi automatisch auf die Klasse A.
    Also kann ich schreiben:

    Quellcode

    1. *refAttribut.bla = 5;

    , sodass bla danach den Wert 5 hat.
  • Jo, so ist es. Vorrausgesetzt natuerlich, dass refAttribut bereits initialisiert ist.
    Also z.B.

    Quellcode

    1. refAttribut = new A();
    2. *refAttribut.bla = 5;


    PS:
    Aber mal angenommen, ich will "Schiffe versenken" programmieren; da besteht doch das Spielfeld aus nur einem Feld (dafür aber aus vielen Koordinaten)!

    Ja, aber das Feld wirst du doch wahrscheinlich auch mit einem zweidimensionalem Array modellieren, oder nicht?
    Also ich wuerde dann nicht die Klassen Feld und Koordinaten benutzen, sondern zum Beispiel Feld und Position.
    Dann wuerde ich halt in Feld als Referenzattribut ein zweidimensionales Array von Positionen machen und dann z.B. Methoden benutzen wie bool position[x][y].istMitSchiffBelegt() und bool position[x][y].wurdeBeschossen() oder so.
    Edit: Oder anders: Man kann die andere Klasse natuerlich auch Koordinaten nennen, aber sie braucht keine Attribute x,y.
    Wo ist der Discord Server

    Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von Skyte ()

  • Man kann die andere Klasse natuerlich auch Koordinaten nennen, aber sie braucht keine Attribute x,y.

    Ja, ich glaub, so mach ich´s wohl.. :)



    Als ich das ganze jetzt allerdings mal ausprobiert hab, kamen folgende Fehlermeldungen (Visual C++ Studio 2008 Express):
    error C2143: Syntaxfehler: Es fehlt ';' vor '*'
    error C4430: Fehlender Typspezifizierer - int wird angenommen. Hinweis: "default-int" wird von C++ nicht unterstützt.

    Datei Spielfeld.cpp:

    C-Quellcode

    1. #include <iostream>
    2. #include <stdlib.h>
    3. using namespace std;
    4. class Spielfeld
    5. {
    6. public:
    7. Spielfeld();
    8. const int Hoehe;
    9. const int Breite;
    10. Koordinate **Koord;
    11. };
    Alles anzeigen


    Datei Koordinate.cpp:

    C-Quellcode

    1. #include <iostream>
    2. #include <stdlib.h>
    3. using namespace std;
    4. class Koordinate
    5. {
    6. public:
    7. Koordinate();
    8. bool verwendet;
    9. };
    Alles anzeigen


    ???

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Alpha Blondy ()

  • Du musst die Klassen untereinander bekannt machen.
    Und in C++ werden solche Deklarationen, wie du sie gemacht hast, in Header Dateien (.h) gespeichert.
    Und diese kann man auch nicht kompilieren, da dort ja gar kein ausfuehrbarer Code drin ist. Wenn man Dateien kompilieren will, brauchen sie ausserdem eine main() Methode.

    Beispiel:

    Koordinate.h:

    Quellcode

    1. class Koordinate {
    2. public:
    3. Koordinate();
    4. ~Koordinate();
    5. private:
    6. bool verwendet;
    7. };

    Koordinate.cpp:

    Quellcode

    1. #include "Koordinate.h"
    2. Koordinate::Koordinate()
    3. :verwendet(false)
    4. { }
    5. Koordinate::~Koordinate()
    6. { }


    Spielfeld.h:

    Quellcode

    1. class Spielfeld {
    2. private:
    3. int breite;
    4. int hoehe;
    5. Koordinate **koord;
    6. public:
    7. Spielfeld();
    8. ~Spielfeld();
    9. Spielfeld(int height, int width);
    10. };
    Alles anzeigen

    Spielfeld.cpp: (wird als Einzige kompiliert)

    C-Quellcode

    1. #include "Koordinate.cpp"
    2. #include "Spielfeld.h"
    3. Spielfeld::Spielfeld()
    4. { }
    5. Spielfeld::Spielfeld(int height, int width)
    6. : hoehe(height),breite(width)
    7. {
    8. int i;
    9. koord = new Koordinate::Koordinate*[height];
    10. for (i = 0; i < height; i++) {
    11. koord[i] = new Koordinate::Koordinate[width];
    12. }
    13. }
    14. Spielfeld::~Spielfeld()
    15. {
    16. int i;
    17. for (i = 0; i < hoehe; i++) {
    18. delete[] koord[i];
    19. }
    20. delete[] koord;
    21. }
    22. int main() {
    23. return 0;
    24. }
    Alles anzeigen
    Wo ist der Discord Server

    Dieser Beitrag wurde bereits 9 mal editiert, zuletzt von Skyte ()

  • Okay, das hab ich kapiert!

    ...doch wenn ich das jetzt teste, kommen massenweise Fehlermeldungen, die sich (fast) alle auf diese Zeile beziehen:

    Quellcode

    1. Koordinate::Koordinate **koord;


    Bin mir aber ziemlich sicher, dass ich alles richtig abgetippt hab usw.
    Ich schick dir einfach mal die Dateien zur Sicherheit (dazu bräucht ich allerdings deine eMai-Adresse)!

    PS: Bin leider bis SO nicht da.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Alpha Blondy ()

  • Alpha Blondy schrieb:

    Bin mir aber ziemlich sicher, dass ich alles richtig abgetippt hab usw.

    Warum machst du nicht einfach Copy and Paste?

    Ich schick dir einfach mal die Dateien zur Sicherheit

    Ist doch nur Text, kannste auch bei nopaste.biz - the classic style pastebin. oder so reinkopieren und die Links hier posten oder mir per PN schicken.

    Und ich wuerd gern die kompletten Fehlermeldungen sehen.

    PS: Weiss nicht, ob das irgend nen Unterschied macht, aber so klappts (bei mir) auch (habs oben geaendert):

    Quellcode

    1. Koordinate **kord;
    Wo ist der Discord Server

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Skyte ()

  • *JUHU* :D:D
    Problem behoben^^

    Nach einigem Ausprobieren bin ich drauf gekommen, dass ich die .cpp-Dateien nicht per #include einbinden darf (wahrscheinlich, weil sie sonst doppelt vorhanden sind oder so).

    Jetzt funzts also endlich!

    Ich denk, jetzt is alles klar.
    Danke Skyte für deine Mühe!

    - ERLEDIGT -

    Greeetz,

    Alpha Blondy
  • Ja, du hattest einiges doppelt, aber dafuer hast du auch

    Quellcode

    1. #pragma once

    benutzt, das sollte Probleme verhindern und bei mir tat es das auch.
    Hab aber auch gelesen, dass #pragma once nicht zum Standard gehoert.

    Aber du hast ja auch meinen Code veraendert. Wenn du ihn mal genau ansiehst, siehst du, dass nix doppelt ist. ;)

    Wie sieht denn dein Code jetzt aus? Und wie hast du die .cpp Dateien eingebunden, wenn nicht mit #include?
    Einfach weglassen konnte ich nicht, da gabs Fehler.

    Edit: Code bekommen. Und anscheinend haben unsere Compiler gravierende Unterschiede. [noparse]:D[/noparse]
    Wo ist der Discord Server

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Skyte ()