kramann.info
© Guido Kramann

Login: Passwort:










6.2 Zeiger und Funktionen

  • Einer Funktion kann ein Objekt als Zeiger übergeben werden.
  • In der UML-Darstellung gibt es keine Zeiger, darum sieht man das nich im UML-Entwurf.
  • Wir greifen erneut Beispiel 3.8/3.9 auf.
  • Betrachten Sie erneut die Implementierung der Funktionen addRechteck(Rechteck r) in der Klasse Werkstueck, die Funktionen plusVektor(Vektor vek) und minusVektor(Vektor vek) in der Klasse Vektor und die Funktion Vektor getSchwerpunkt() in der Klasse Rechteck in Kapitel 3.9.
  • Die dort verwendete intuitiv gut nachvollziehbare Umsetzung, bei der sogenannte Referenzen auf Objekte übergeben werden, wollen wir ab jetzt nicht weiterverfolgen.
  • Stattdessen verändern wir die Implementierung nun so, dass den betreffenden Funktionen Zeiger auf die Objekte übergeben werden.
  • An der UML-Darstellung ändert sich nichts:
UML Klassendiagramm für das Schwerpunktprogramm

Bild 6.2-1: UML Klassendiagramm für das Schwerpunktprogramm

  • Die Implementierung aber ist nun etwas anders:
  • Statt Objekte werden Zeiger auf Objekte übergben.
  • Bei den in der main-Methode vordefinierten Rechtecken, müssen die Adressen bei der Funktionsübergabe mit & ausgelesen werden, wie wir das bei den generischen Datentypen int, double, etc. kennen.
  • Wichtig: Bei der Version aus Kapitel 3.9 hatten wir "Glück", dass das Programm nicht abgestürzt ist.
  • Wenn Objekte nicht mit new erzeugt werden, sind sie nur so lange gültig, wie die Funktion, oder das Objekt in dem sie erstellt wurden.
  • Da die main-Methode, in der die Rechtecke erzeugt wurden für die Laufzeit des Programms nicht verlassen wird, wird der Stack-Speicher dieser Objekte auch zur Laufzeit des Programms nicht zerstört.
  • Bei anderen Verhältnissen können wir auch einmal Pech haben.
  • Wir wollen uns so eine ungünstige Situation einmal für ein einfaches und dann für ein komplizierteres Beispiel anschauen und sie durch Verwendung von new und Zeigern reparieren.
  • Die Lebensdauer von Objekte kann dabei mit einer weiteren UML-Diagramm-Variante veranschaulicht werden, dem UML-Sequenz-Diagramm.
  • Die unten dargestellte Veränderung des Codes von 3.9. verdeutlicht zwar die Syntax von Zeigern, die auf Objekte verweisen, nutzt aber nicht die dadurch gewonnenen neuen Möglichkeiten aus.
  • Deshalb werden wir nach dem kleinen Beispiel zur Lebensdauer von Objekten eine verbesserte Version zur Schwerpunktberechnung vorstellen.


#include <iostream>
#define MAXRECHTECK 100;

using namespace std;

class Vektor
{
    public:
        double x;
        double y;

        Vektor()
        {
            x = 0.0;
            y = 0.0;
        }
        Vektor(double inx, double iny)
        {
            x = inx;
            y = iny;
        }
        void malSkalar(double skalar)
        {
            x*=skalar;
            y*=skalar;
        }
        void plusVektor(Vektor* vek)
        {
            x+=vek->x;
            y+=vek->y;
        }
        void minusVektor(Vektor* vek)
        {
            x-=vek->x;
            y-=vek->y;
        }
};

class Rechteck
{
    public:
        Rechteck()
        {
        }
        Rechteck(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
        {
            ort1.x = x1;
            ort1.y = y1;
            ort2.x = x2;
            ort2.y = y2;
            ort3.x = x3;
            ort3.y = y3;
            ort4.x = x4;
            ort4.y = y4;       
        }
        Vektor* getSchwerpunkt()
        {
            Vektor* ergebnis = new Vektor();

            ergebnis->plusVektor(&ort1);
            ergebnis->plusVektor(&ort3);
            ergebnis->malSkalar(0.5);

            return ergebnis;
        }
        double getFlaeche()
        {
            Vektor ergebnis;
            ergebnis.plusVektor(&ort3);
            ergebnis.minusVektor(&ort1);
            return ergebnis.x*ergebnis.y;
        }
        
    private:
        Vektor  ort1,ort2,ort3,ort4;
        double flaeche;
};

class Werkstueck
{
    private:
        int anzahl;
        Rechteck* re[100];
    public:
        Werkstueck()
        {
            anzahl = 0;
        }
        void addRechteck(Rechteck* r)
        {
            re[anzahl] = r;
            anzahl++;
        }

        Vektor getSchwerpunkt()
        {
            Vektor sp;
            Vektor* merker;
            double nenner;

            for(int i=0;i<anzahl;i++)
            {
                merker = re[i]->getSchwerpunkt();
                merker->malSkalar(re[i]->getFlaeche());
                sp.plusVektor(merker);
                nenner+=re[i]->getFlaeche();
            }    
            sp.malSkalar(1.0/nenner);
            return sp;
        }        
};

int main(void)
{
    Werkstueck meinWerkstueck;

    Rechteck r1(0.0,2.0,4.0,2.0,4.0,5.0,0.0,5.0);
    Rechteck r2(2.0,0.0,4.0,0.0,4.0,2.0,2.0,2.0);
    Rechteck r3(4.0,2.0,7.0,2.0,7.0,3.0,4.0,3.0);
    Rechteck r4(4.0,3.0,6.0,3.0,6.0,7.0,4.0,7.0);
    Rechteck r5(4.0,7.0,7.0,7.0,7.0,8.0,4.0,8.0);

    meinWerkstueck.addRechteck(&r1);    
    meinWerkstueck.addRechteck(&r2);    
    meinWerkstueck.addRechteck(&r3);    
    meinWerkstueck.addRechteck(&r4);    
    meinWerkstueck.addRechteck(&r5);    

    Vektor schwerpunkt = meinWerkstueck.getSchwerpunkt();

    cout<<"Der Schwerpunkt des Werkstuecks liegt bei xs="<<schwerpunkt.x<<" ys="<<schwerpunkt.y<<endl;

    return 1;
}

 

Code 6.2-1: Schwerpunktberechnung unter Verwendung von Zeigern auf Objekte.