C++-Programmierung/ Brüche/ Die Methoden

Aus Wikibooks


In diesem Kapitel werden Sie mit den Methoden bekannt gemacht, die unsere Bruch-Klasse zur Verfügung stellt. Grundlegend tauchen im Zusammenhang mit Brüchen zwei Begriffe auf: „Erweitern“ und „Kürzen“. Im Zusammenhang mit diesen beiden finden sich wiederum die Begriffe „kleinstes gemeinsames Vielfaches“ und „größter gemeinsamer Teiler“. Wir haben uns bei den Vorüberlegungen dafür entschieden, das Erweitern wegzulassen, bei der Addition und Subtraktion brauchen wir es aber. Im folgenden werden das „kleinste gemeinsame Vielfache“ und der „größte gemeinsame Teiler“ mit kgV und ggT abgekürzt.

Wir haben also die folgenden Methoden:

  • ggT
  • kgV
  • kuerzen

Dazu kommen noch zwei Zugriffsfunktionen, da sich der Benutzer unserer Klasse vielleicht für Zähler und Nenner des Bruchs interessiert:

  • zaehler
  • nenner

Zwei dieser fünf Methoden müssen aber gleich wieder gestrichen werden. ggT und kgV sind zwar in Zusammenhang mit Brüchen hilfreich, aber sie beschreiben allgemeine mathematische Funktionen, die nicht ausschließlich in Zusammenhang mit Brüchen eingesetzt werden. Daher sind diese beiden Funktionen unter der Überschrift Methoden etwas fehlpositioniert, da sie keine Member der Klasse Bruch sind.

Zugriff[Bearbeiten]

Die beiden Zugriffsmethoden tun nichts weiter, als Zähler und Nenner des Bruchs zurückzugeben, daher schreiben wir sie direkt in die Klassendeklaration.

class Bruch{
public:
    Bruch(int zaehler = 0, unsigned int nenner = 1);

    int          zaehler()const {return zaehler_;}
    unsigned int nenner()const  {return nenner_;}

private:
    int          zaehler_;
    unsigned int nenner_;
};

Wie Sie sehen, haben die beiden Methoden den gleichen Rückgabetyp wie die Variablen, die sie repräsentieren. Achten Sie bitte auch darauf, dass beide als const deklariert sind, da sie keine Variable innerhalb der Klasse verändern.

ggT()[Bearbeiten]

In der Schule haben Sie sicher gelernt, dass sich der ggT (größte gemeinsame Teiler) durch Primfaktorzerlegung ermitteln lässt. Dieses Verfahren ist allerdings denkbar ungünstig, um es auf einem Rechner umzusetzen. Sie müssten zunächst einmal die Primzahlen berechnen und das dauert, zumal Sie ja gar nicht wissen, wie viele Primzahlen Sie überhaupt benötigen.

Deshalb bedienen wir uns eines anderen Verfahrens, des euklidischen Algorithmus. Eine Verbesserung dieses Verfahrens ist der steinsche Algorithmus, aber für unsere Zwecke reicht ersterer. Sie dürfen die Klasse natürlich gerne dahingehend verbessern, dass Sie den steinschen Algorithmus einsetzen.

Der euklidische Algorithmus beruht auf zwei Eigenschaften des größten gemeinsamen Teilers:

Wenn Sie eine genaue Beschreibung wünschen, dann schauen Sie sich doch mal den entsprechenden Wikipediaartikel an.

unsigned int ggT(unsigned int a, unsigned int b){
    if(b == 0)
        return a;
    else return ggT(b, a % b);
}

Beachten Sie, dass diese Funktion rekursiv funktioniert. Die Implementierung als einfache Schleife wäre ebenfalls möglich gewesen, aber sie ist etwas unübersichtlicher und dank Optimierung ist die rekursive Variante nur unwesentlich langsamer. Wenn Sie nicht mehr wissen, was rekursive Funktionen sind, dann werfen Sie noch mal einen Blick auf das Kapitel Rekursion im Abschnitt „Weitere Grundelemente“.

kgV()[Bearbeiten]

Das kgV lässt sich ganz einfach berechnen, wenn Sie den ggT kennen. Daher schreiben wir die Funktion mit Hilfe der eben erstellten ggT-Funktion.

unsigned int kgV(unsigned int a, unsigned int b){
    return (a * b) / ggT(a, b);
}
Hinweis

Damit kgV() auf ggT() zugreifen kann, muss dieses natürlich bekannt sein. Sie müssen die Deklaration immer geschrieben haben, bevor Sie das entsprechende Element verwenden.

kuerzen()[Bearbeiten]

kuerzen() ist nun endlich mal wirklich eine Memberfunktion (oder auch Methode) von Bruch. Da sie somit direkten Zugriff auf die Variablen hat, die sie verändern soll, braucht sie keine Argumente und auch keinen Rückgabewert.

class Bruch{
public:
    Bruch(int zaehler = 0, unsigned int nenner = 1);

    int          zaehler()const {return zaehler_;}
    unsigned int nenner()const  {return nenner_;}

private:
    void kuerzen();

    int          zaehler_;
    unsigned int nenner_;
};

void Bruch::kuerzen(){
    unsigned int tmp(ggT(zaehler_, nenner_));
    zaehler_ /= tmp;
    nenner_  /= tmp;
}

Da kuerzen() eine Methode ist, die nur innerhalb der Klasse nach einer Rechenoperation aufgerufen wird, deklarieren wir sie im privaten Bereich der Klasse.