8. Objektorientierte Programmierung
 
zurück
8.4 Vererbung


Eine weitere Eigenschaft der "tagged"-Verbundtypen, also der Klassen von Ada 95, ist die Möglichkeit der Programmierung durch Erweiterung ("programming by extension").

Durch die Ableitung (Vererbung) von einem vorhandenen "tagged"-Verbundtyp wird ein neuer "tagged"-Verbundtyp erzeugt, der mit neuen Verbundtyp-Elementen und Operationen versehen werden kann (derived_type_definition <BNF>). Klassen, die von anderen Klassen abgeleitet werden, bezeichnet man als "abgeleitete Klassen", die Ursprungsklasse heißt "Basisklasse".

Man deklariert einen neuen "tagged"-Verbundtyp (eine abgeleitete Klasse) unter Verwendung einer vorhandenen Klasse und "erbt" sozusagen die Verbundtyp-Komponenten und alle darauf definierten Operationen.


Beispiel: Erweiterung einer Basisklasse

type Punkt is tagged record -- Basisklasse Punkt
   x,y : Integer;
   Farbe : Farbliste;
end record;

type Linie is new Punkt with record -- von Punkt abgeleitete Klasse
   x1,y1 : Integer; -- die neuen Koordinaten
end record;

Der Datentyp "Linie" ist eine Klasse, die von der Basisklasse "Punkt" abgeleitet wurde. "Linie" besteht nun insgesamt aus fünf Verbundtyp-Elementen und verhält sich so, als wäre "Linie" als Verbundtyp mit fünf Elementen deklariert worden. Die Verbundtyp-Komponenten "Farbe", "x" und "y" wurden von der Basisklasse "Punkt" an die Klasse "Linie" vererbt, und die Verbundtyp-Komponenten "x1" und "y1" wurden hinzugefügt.

Bei der weiteren Verwendung von "Linie" besteht aus Benutzersicht kein Unterschied zwischen diesem Typ und einem äquivalenten Typ mit fünf Elementen, der auf herkömmliche Art und Weise (also ohne die Angabe "tagged") deklariert wurde.

Aufbauend auf der Basisklasse Punkt werden die Spezifikation und der Rumpf für Linie gebildet.



package Punkt is     -- Spezifikation von <Punkt>:

   type Farbliste is (Rot, Gelb, Grün, Undefiniert );

   type Punkt is tagged record
      X, Y : Integer;
      Farbe : Farbliste;
   end record;

   procedure Erzeuge (P : IN OUT Punkt; X_Koord,Y_Koord : IN Integer);

   procedure Farbe_ändern (P : IN OUT Punkt; Neue_Farbe : IN Farbliste);

   procedure Zeichnen (P : IN Punkt);

end Punkt;



with Punkt;
-- Spezifikation von <Linie>
package Linie is

    type Linie is new Punkt.Punkt with record
       X1, Y1 : Integer;
    end record;

    procedure Erzeuge (L : IN OUT Linie;´X_Koord, Y_Koord, X1_Koord, Y1_Koord : IN Integer);

    procedure Zeichnen (L : IN Linie);

end Linie;


Die Prozeduren "Erzeuge" und "Zeichnen" müssen neu erstellt werden, weil sie spezielle Aufgaben haben (Manipulation der Elemente "x1" und "y1"), die von den überladenen Prozeduren der Klasse "Punkt" nicht übernommen werden können.

Die Prozedur "Farbe_aendern" der Klasse "Punkt" wird jedoch nicht neu erstellt oder überladen, weil sie sowohl für Objekte der Klasse "Punkt" als auch für sämtliche abgeleiteten Klassen richtig funktioniert. Grund: "Farbe_aendern" manipuliert nur das Element "Farbe", das sowohl in der Basisklasse als auch in allen abgeleiteten Klassen enthalten ist.

Rumpf von <Linie> :

with Text_IO, Punkt;

package body Linie is
   procedure Erzeuge (L : IN OUT Linie; X_Koord,Y_Koord,X1_Koord,Y1_Koord : IN Integer) is
   begin
      L.Farbe := Punkt.Undefiniert;
      L.X := X_Koord;
      L.Y := Y_Koord;
      L.X1 := X1_Koord;
      L.Y1 := Y1_Koord;
      Text_IO.Put_Line ("Erzeuge Linie");
   end;

   procedure Zeichnen (L : IN Linie) is
   begin
      Text_IO.Put_Line ("Zeichne Linie" & " " & Integer'Image (L.X) & " " & Integer'Image (L.Y) & " " &
              Integer'Image (L.X1) & " " & Integer'Image (L.Y1) & " " & Punkt.Farbliste'Image (L.Farbe) );
    end;
end Linie;

Duch die Vererbung bekommt eine abgeleitete Klasse die Möglichkeit, auf Daten und Komponentenfunktionen einer anderen Klasse zuzugreifen. Für neue Aufgaben stellt sie eigene Komponentenfunktionen zur Verfügung.

Beachte: Durch die Möglichkeit, vorhandene Klassen durch Vererbung zu erweitern, kann man die Funktionalität von vorhandenen Klassen erweitern, ohne Änderungen in der bestehenden oder übernommenen Software vornehmen zu müssen. Dieses wirkt sich positiv auf die Wartbarkeit aus, weil Änderungen in vorhandenen Programmteilen weitgehend entfallen.
  • Ada 95 unterstützt nur die einfache Vererbung (Single Inheritance), wobei eine neue Klasse die Datentypen und Operationen von genau einer anderen Klasse erweitert. Man kann also zwei unterschiedliche Klassen nicht zu einer neuen dritten Klasse vermischen. Die entstehende Klassenhierarchie hat daher Baumstruktur.
  • Duch die Vererbung bekommt die neue Klasse die Möglichkeit, auf Daten und Komponentenfunktionen einer anderen Klasse zuzugreifen. Diese geerbten Bezeichner sind sichtbar, wenn die Deklaration der neuen Klasse nicht im privaten Teil des sie umgebenden Pakets vorgenommen wird. Ohne privaten Teil sind alle in der Spezifikation aufgeführten Daten und Komponentenfunktionen öffentlich, was die Manipulation der Klassendaten unter Umgehung der Komponentenfunktionen ermöglicht.
    Ein sauberer Entwurf sieht vor, daß nur das sichtbar sein darf, was zur Manipulation der Klassendaten unbedingt benötigt wird.
Die Möglichkeit, vorhandene Klassen durch Vererbung zu erweitern, erlaubt es, die Funktionalität von Klassen zu erweitern, ohne die dazu notwendigen Änderungen direkt in der bestehenden oder übernommenen Software vornehmen zu müssen.

Angenommen, zwei Klassen "Punkt" und "Linie" und die zugehörigen Operationen wären fertig und getestet in Paketen enthalten, dann kann die Funktionalität der Klassen durch Einführung einer neuen Klasse "Rechteck" erweitert werden, ohne die Pakete "Punkt" und "Linie" ändern oder rekompilieren zu müssen.

Für jedes Objekt einer Klasse wird immer die passende Prozedur aufgerufen. Für ein Objekt der Klasse "Linie" wird zum Erzeugen immer die Prozedur "Erzeuge" der Klasse "Linie" aufgerufen und nicht eine gleichnamige Prozedur einer anderen Klasse.

Die Prozedur "Farbe_aendern" der Klasse "Punkt" ist nur einmal vorhanden, weil sie sowohl für Objekte der Klasse "Punkt" als auch für sämtliche abgeleiteten Klassen richtig funktioniert.
Grund: "Farbe_aendern" manipuliert nur das Element "Farbe", das sowohl in der Basisklasse als auch in allen Unterklassen (abgeleiteten Klassen) enthalten ist.

Die Klasse "Rechteck" hat keine neuen Datentypen, die die Klasse erweitern. Die Koordinaten (x,y, x1,y1) werden aber für ein Rechteck anders als bei einer Linie interpretiert, so daß sich die Notwendigkeit für eine neue Klasse ergibt. Weil keine neuen Datentypen dazukommen, ergibt sich folgende Schreibweise (record_definition <BNF>):


with Linie;
-- Spezifikation von <Rechteck>:
package Rechteck is
   type Rechteck is new Linie.Linie with null record;

    procedure Erzeuge ( R : IN OUT Rechteck; x_Koord,y_Koord,x1_Koord,y1_Koord : IN Integer );

    procedure Zeichnen ( R: Rechteck );
end Rechteck;


with Text_IO, Linie, Punkt;
-- Rumpf von <Rechteck>:
package body Rechteck is
   procedure Erzeuge (R : IN OUT Rechteck; X_Koord,Y_Koord,X1_Koord,Y1_Koord : IN Integer) is
   begin
      R.Farbe := Punkt.Undefiniert;
      R.X := X_Koord;
      R.Y := Y_Koord;
      R.X1 := X1_Koord;
      R.Y1 := Y1_Koord;
      Text_IO.Put_Line ("Erzeuge Rechteck");
   end;
   procedure Zeichnen (R : Rechteck) is
   begin
      Text_IO.Put_Line ("Zeichne Rechteck" & " " & " Ecke_1=" & Integer'Image (R.X) & " " &
                         Integer'Image (R.Y) & " " & " Ecke_2=" & Integer'Image (R.X1) & " " &
                         Integer'Image (R.Y1) & " " & Punkt.Farbliste'Image (R.Farbe) );
   end;
end Rechteck;



 
zurück
 Index   Ada Tour - Dokumentation  
© 2003 Förderverein Ada Deutschland e.V.