Announcement

Collapse
No announcement yet.

Class_Bruch

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Class_Bruch

    Hallo Community,
    ich habe heute angefangen mir C# beizubringen.
    Ich versuche gerade im Vorfeld ein paar Übungsaufgaben bereits zu lösen damit ich später nicht unter so großen Druck gerate.

    Hier mal meine Aufgabenstellung:

    Programmieren Sie im namespace Test die Klasse Bruch mit den
    erforderlichen Konstruktoren.
    Gehen Sie schrittweise vor. Beginnen Sie mit einer Klasse, die nur die
    Attribute und die get- und set-Methoden enthält. Testen Sie die
    Klasse mit einem Hauptprogramm, in dem Sie einige Objekte
    erzeugen.
    Ergänzen Sie die restlichen Methoden sowie geeignete Anweisungen
    zum Test im Hauptprogramm. Dieses soll aus einer Schleife bestehen,
    in der jeweils Zähler und Nenner eingegeben und mit der Funktion
    ausgabe() wieder auf den Bildschirm ausgegeben werden. Wenn
    Zähler und Nenner mit Null eingegeben werden, endet das
    Programm.
    Optional:
    1. Erweitern Sie die Klasse um eine Methode operator+, mit
    der zwei Brüche addiert werden. Ändern Sie das
    Hauptprogramm, so dass Sie diese Funktion sinnvoll testen
    können.
    2. Fügen Sie der Klasse eine statische Variable anzahl hinzu,
    mit der die Zahl der existierenden Bruch-Instanzen gezählt
    wird.
    3. Entwickeln Sie eine grafische Benutzeroberfläche!

    Dazu gabs noch dieses Bild:

    UE01 Klasse Bruch


    • Attribute (private)
    – zaehler: int
    – nenner: int

    • Konstruktoren
    – Bruch() 0/1
    – Bruch(3) 3/1
    – Bruch(7 3) 7/3

    • Methoden
    – get/set‐Funktionen für die Attribute
    – ausgabe() gibt den Bruch aus, z.B. 7/3
    So da ich Null vorkenntnisse habe in C# allerdings schon etwas Programmiert habe möchte ich mal meinen Lösungsansatz vorstellen:



    1.) Zuerst habe ich eine neue Class Angelegt mit dem Namen "Class_Bruch"

    Code:
    using System;
    
    namespace Übung01_ClassBruchForm
    {
        class Class_Bruch
        {
            private int zaehler;
            private int nenner = 1;
    
            public int Zaehler
            {
                get { return zaehler; }
                set { zaehler = value; }
            }
    
            public int Nenner
            {
                get { return nenner; }
                set { if (value != 0) nenner = value; }
            }
    
            public static void Ausgabe()
            {
                
            }   
        }
    }
    Wie ich auf Private Datentypen zugreife mittels Propertys scheine ich verstanden zu haben ( hoffs zumindest ^^).

    Habe in meiner Main Form nun zwei Textboxen für die Zahl Zähler und Nenner
    welche ich so übergebe:

    Code:
    Class_Bruch Bruch = new Class_Bruch();
                    Bruch.Nenner = int.Parse(txtNenner.Text);
                    Bruch.Zaehler = int.Parse(txtZaehler.Text);
    Wo es nun bei mir harpert ist bei der Ausgabe.
    Ich weis nämlich nicht wie ich da eine sinvolle Methode Ausgabe in die Klasse einbauen soll.

    Ich hätte in meiner mainForm eher etwas in der Richtung gemacht:

    Code:
    txtErgebniss.Text = Convert.ToString(Bruch.Zaehler)+"/"+
                                    Convert.ToString(Bruch.Nenner);
    Hätte aber jetzt keine Ahnung wie ich das als Methode in die Klasse einbaue.

    Die Konstruktoren werde ich auch hinbekommen, hilfe wäre mich echt recht bei der Ausgabe.

    Gruß Vertax
    Zuletzt editiert von Vertax; 23.03.2010, 20:27. Reason: "Zitat" ist kein "Code" (einen Button weiter links)

  • #2
    Hallo,

    was der Aufgabensteller sich unter Ausgabe vorstellt, ist mir auch etwas schleierhaft. Ich hätte ebenfalls eher an ToString gedacht. Also verbinde das doch einfach:
    [highlight=c#]public override string ToString() // ähnlich wie bei deiner Idee, aber "richtig"
    {
    return Zaehler.ToString() + "/" + Nenner.ToString();
    // ToString gibt es für alles, also benutze es einfach
    }

    public string Ausgabe() // ich wüsste nicht, wieso das static sein sollte
    {
    return this.ToString();
    }[/highlight]
    Tipp zu den Konstruktoren: Definiere einen, der Zähler und Nenner übernimmt.

    Gruß Jürgen

    Comment


    • #3
      Originally posted by Jürgen Thomas View Post
      [highlight=c#]public override string ToString() // ähnlich wie bei deiner Idee, aber "richtig"
      {
      return Zaehler.ToString() + "/" + Nenner.ToString();
      // ToString gibt es für alles, also benutze es einfach
      }

      public string Ausgabe() // ich wüsste nicht, wieso das static sein sollte
      {
      return this.ToString();
      }[/highlight]
      Hi, danke für deine Schnelle Antwort, aber ich verstehe nicht ganz den Code.
      Bin gerade beim Kapitel 2 in meinem Galileobook.

      In der Uni machen wir aber immer alles Querbeet, deshalb muss ich mir immer sachen aus späteren Kapiteln raussuchen und kurz anreizen, damit ich die Übungsaufgaben fertig machen kann.

      was bedeutet den:

      Code:
      public override string ToString()
      und an was wird es dann returnt?

      Code:
       return Zaehler.ToString() + "/" + Nenner.ToString();
      Und wie kann dann eine andere Methode das Ergebniss über this ausgeben?

      Comment


      • #4
        Jede Klasse erbt implizit von Object. In Object ist eine Funktion ToString() als virtual definiert. Normalerweise liefert die Funktion den Namen der Klasse zurück. Wenn Du diese in der Unterklasse (hier Bruch) durch override überschreibst, dann wird diese Funktion anstatt der Funktion in der Oberklasse (hier Object) verwendet.
        Die Funktion Ausgabe braucht man eigentlich nicht zwingend, da ja ToString() dann die Arbeit schon erledigt. Deswegen wird deligiert Ausgabe die Berechnung einfach weiter an ToString()

        Comment


        • #5
          Hallo,

          das Wichtigste hat fanderlf schon gesagt. Als Ergänzung dazu:

          und an was wird es dann returnt?
          Immer dorthin, von wo es aufgerufen wird. return ist das Schlüsselwort, das den dahinterstehenden Wert als Ergebnis der Methode zurückgibt.

          Code:
          return this.ToString();
          Und wie kann dann eine andere Methode das Ergebniss über this ausgeben?
          this ist nur von Bedeutung an der Stelle, wo es steht. Es ist ein Verweis "auf sich selbst", also auf das konkrete Objekt. Diese Zeile ist so zu lesen: Wenn das Programm hierher kommt, soll es seine eigene ToString-Methode benutzen und deren Ergebnis zurückgeben. Im aufrufenden Programmteil steht etwas wie meinBruch.Ausgabe(); es wird also die Ausgabe-Methode des konkreten Objekts meinBruch benötigt.

          this ist fast immer überflüssig, auch in diesem Fall. Ich hatte es ausdrücklich geschrieben, um die Zusammenhänge deutlich zu machen. Möglicherweise hättest du es leichter verstanden, wenn ich es weggelassen hätte.

          Originally posted by Vertax View Post
          In der Uni machen wir aber immer alles Querbeet, deshalb muss ich mir immer sachen aus späteren Kapiteln raussuchen und kurz anreizen, damit ich die Übungsaufgaben fertig machen kann.
          Das ist natürlich ein Problem. Aber so umfangreich wie .NET ist, kann es kaum anders gelöst werden. Ich schreibe zz. an [wikibooks] Arbeiten mit .NET und habe genau dasselbe Problem: Wie kann ich etwas mit Beispielen erklären ohne Vorgriff auf viel spätere Kapitel?

          Viel Erfolg! Jürgen

          Comment


          • #6
            Hallo nochmal, habe nun die Übung dank eurer hilfe vorzeitig abgeschlossen, fände es aber ganz nett wenn sich jemand mal das ganze ansehen könnte was ich produziert habe

            Ich habe ja die Aufgabenstellung ganz oben schonmal gepostet. Könnt ja mal bitte sagen ob das in eueren Augen so korrekt ist oder eventuell verbesserungs Vorschläge habt.

            Hätte auch noch eine gezielte Frage.
            Wenn ich in meinem Programm einen Bruch Eingebe und auf Bruch erstellen drücke, wird ja eine neue Instanz aus der Klasse gebildet. Wenn ich danach andere ZAhlen eintrage, wird dann wieder eine neue Instanz gebildet oder wird die alte einfach Überschrieben?

            Wenn eine neue angelegt wird, kann ich dann überhaupt noch auf die alte zugreifen, da ja beide mit Class_Bruch Bruch = new Class_Bruch erstellt wird.

            Vielen dank falls sich jemand die mühe machen könnte.
            Vertax
            Attached Files

            Comment


            • #7
              Code:
              Wenn eine neue angelegt wird, kann ich dann überhaupt noch auf die alte zugreifen, da ja beide mit Class_Bruch Bruch = new Class_Bruch erstellt wird.
              Die offizielle Antwort ist nein. Eine nicht mehr referenzierte Klasse ist nicht mehr erreichbar und wird irgendwann zerstört. Die Antwort impliziert natürlich das es einen inoffiziellen ~bösen~ Weg gibt doch ranzukommen aber es gibt keinen sinnvollen <grund warum man das tun sollte, also belassen wir es lieber beim nein.

              Dein Code ist im weitestens Sinne ok Es gibt ein paar stillistische Sachen und kleinere Fehler die ich hier kurz anspreche die machen denn Code aber nicht per se schlecht. Das meiste sind eher Best Practises die von der Mehrzahl der Programmierer auch so verwendet werden würden und somit für diese deinen Code leichter lesbar machen.

              - Bei boolschen Vergleichen vergleichst du bereits boolsche Wert mit true und false. Das ist unnötig der Ausdruck ist vorher ja bereits ein bool.

              Also z.b.
              Code:
              if (ckBruch1.Checked == false & ckBruch2.Checked == false)
              sollte man einfacher
              Code:
              if (!ckBruch1.Checked && !ckBruch2.Checked)
              schreiben.

              - Auch benutzt du den & als AND Operator. Es ist üblicher den && Operator zu verwenden den meistens brauchst du die Auswertung des folgenden Ausdrucks nicht wenn der erste schon falsch ist. Es ist einfach den & Operator falsch einzusetzen wenn man nicht nur boolsche Ausdrücke hat sondern auch andere Ausdrücke die erste unmittelbar zu einen boolschen Ausdruck werden. Und schwubs hat man ein bitweises AND(wofür & bei anderen Datentypen steht) ausgeführt obwohl man ein logisches AND wollte. Lieber gleich && verwenden.

              - Die verwendung der Convert Klasse zum Konvertieren zu string ist eher ungewöhnlich. Du solltest besser diesen Code
              Code:
              Convert.ToString(Bruch.Instance)
              als
              Code:
              Bruch.Instance.ToString()
              schreiben.

              - strings können nicht nur leer sondern auch null sein.
              Deshalb testet man üblicherweise nicht direkt auf einen Leerstring sondern benutzt die String.IsNullOrEmpty Methode. Aus
              Code:
              if (txtNenner2.Text == "")
              würde also z.B.
              Code:
              if (string.IsNullOrEmpty(txtNenner2.Text))
              - Der Namespace enthält ein Ü. Das wird unterstütz ich würde trotzdem (noch) von der Benutzung von Umlauten oder sonstigen eigentlich gültigen Sonderzeichen abraten. Es gibt soviele Fallstricke mit sonstigen Tools die man im Umfeld der Softwareentwicklung benutzt die damit nicht (oder falsch) umgehen, insbesondere Versionscontrolsysteme, das man Umlaute vermeiden sollte. Es gibt ja im Sourcecode auch keinen zwingend Grund die zu verwenden. Meine Aussage wird hoffentlich in Zukunft ungültig ich warte aber schon seit Jahren auf einen funktionierend Toolchain der garantiert in jeder Lage mit Unicode umgehen kann so das ich da eher pessimistisch bin

              - Den Instanzzähler erhöhst du immer nach dem Erstellen der Klasse von auserhalb. Das solltest du eher in den Konstruktor verlagern um dir diese extra Codezeile zu ersparen und den Code robuster zu machen. Den die extra Code zeil ekönnte man vergessen ist sie einmal im KOnstruktor kann dir das nicht mehr passieren. Ist dir bewußt das du einen Konstruktor aus einem anderen Konstruktor aufrufen kannst?

              Deine Konstruktoren würde ich so umschreiben.

              Code:
                      public Class_Bruch() : this(0,1) {}
              
                      public Class_Bruch(int zaehler) : this (zaehler, 1)  {}
              
                      public Class_Bruch(int zaehler, int nenner)
                      {
                          this.nenner = nenner;
                          this.zaehler = zaehler;
                      }
              - Der Instanzzähler wird bei dir auch immer nur erhöht. Du solltest wenn du wirklich die im Speicher existierenden Instanzen zählen willst (da ist die Aufgabenstellung nicht ganz klar) den im Finalizer wieder erniedrigen. Wenn es dir nur um die referenzierten Instanzen geht müßte deine Klasse IDisposable implementieren. Das wäre aber was für eine spätere Übung

              - Den Code für Bruch1 solltest du noch entsprechend Bruch 2 nachziehen damit der auch funktioniert.


              Jetzt habe ich aber genug geschrieben will dich nicht frustrieren(dazu gibts auch keinen Grund).

              Comment


              • #8
                Vielen dank für deine Hilfe, werde mir deine Anmerkungen merken und in der Zukunft umsetzen.

                Comment

                Working...
                X