Eine kleine Einführung in Objektorientiertes Programmieren

In fünf aufeinander aufbauenden Programmbeispielen werden die Grundkonzepte des objektorientierten Programmierens unter Verwendung von TopPASCAL erklärt. TopPASCAL lehnt sich in Bezug auf OOP stark an OBERON-2 an.

In der Objektorientierten Sichtweise verschmelzen die Daten und die darauf operierenden Algorithmen zu neuen Einheiten, den Objekten:

Objekt = Daten und Algorithmen

Im Unterschied zu einem konventionellen Datensatz besitzt ein Objekt eine gewisse Intelligenz (oder Autonomie), es kann sich beispielsweise selber darstellen, sich selber mit Werten belegen (z.B. durch die speziell zum Objekt passende Datenmaske), sich selber abspeichern, sich duplizieren (klonen) etc.

OOPDemo1

Unter einer Objektklasse (kurz Klasse) versteht man den Datentyp für gleichartige Objekte. Eine Klasse wird in TopPASCAL als record-Typ vereinbart. Z.B. type TKreis=record xm,ym,r:real end; Die record-Komponenten xm,ym und r heissen in der OOP Terminologie Instanzvariablen.
Mit
var k1,k2:TKreis; deklariert man 3 Objekte oder Instanzen der Klasse TKreis. Eine an eine Klasse gebundene Prozedur oder Funktion heisst Methode. Beispiel für die Vereinbarung einer Methode:
procedure (k:TKreis).draw; begin uCircle(k.x,k.y,k.r) end; Der Aufruf der draw-Methode für das Objekt k1 der Klasse TKreis erfolgt mit k1.draw. In OOP Sprechweise sagt man: Das Objekt k1 erhält eine draw-Message.

OOPDemo2

Angenommen, die Klasse TKreis wäre ein Teil eines Systems für verschiedene geometrische Figuren. Die Vereinbarung der Klassen sähe dann vielleicht so aus:
type TFigur = record ... end; TKreis=record(TFigur) end; TQuadrat=....
Die Klassen TKreis und TQuadrat sind zwei versch.
Typerweiterungen (oder Subklassen) von TFigur, umgekehrt nennt man TFigur Basisklasse oder Elternklasse von TKreis und TQuadrat. Instanzen von TFigur sollten nicht benutzt werden, TFigur ist zu wenig spezifiziert und heisst deshalb abstrakte Klasse.

OOPDemo3

Eine Subklasse übernimmt sämtliche Instanzvariablen und Methoden ihrer Elternklasse (Vererbung). Wird für die Subklasse eine Methode der Elternklasse erneut definiert, so wird letztere überschrieben. Beim Aufruf dieser Methode für ein Objekt der Subklasse wird die neuvereinbarte Routine abgearbeitet (Statische Bindung). Möchte man für ein Objekt der Subklasse die zur Elternklasse gehörige Methode ausführen, so ermöglicht dies der parent-Operator. (z.B. x.parent.init)
Die Vereinbarung von Methoden, d.h. deren Implementation oder "forward"-Referenz, muss unmittelbar nach der Vereinbarung der betreffenden Klasse erfolgen.

OOPDemo4

Funktions- und Prozedur-Methoden
forward-Referenzen in Klassenvereinbarungen zur Trennung von Schnittstellenbeschreibung und Implementation

OOPDemo5

Dynamische Objekte (realisiert durch einen Zeiger auf eine Objektklasse
dynamische Bindung: array zur Speicherung verschiedener Objekte
hastype-Methode zur Feststellung des dynamischen Typs

 


{Erstes Vorstellen von Objekt/Objektklasse, Methodenvereinbarung
 und Methodenaufruf}
program OOPDemo1;
  type TPerson  =record                {Objektklasse TPerson}
                   name:string 
                  end;
       
  procedure (p:TPerson).lies;          {Methode lies}
    begin
      write('Name:');readln(p.name);
    end;
  procedure (p:TPerson).schreib;       {Methode schreib}
    begin
      writeln(p.name);
    end;
    
  var p:TPerson;                       {Objekt p}
  
begin
  p.lies;p.schreib;                    {Methodenaufrufe}
end. 

zum Start

{Typerweiterung, abstrakte Klasse, Basisklasse, Subklasse}
program OOPDemo2;
  type TPerson  =record               {Basisklasse TPerson: abstrakt,}
                   name:string        {nur zur Ableitung der folgenden}
                  end;                 {Objektklassen verwendet.}
       TSchueler=record(TPerson)      {Subklasse, Typerweiterung von TPerson}
                   stufe:integer;
                 end; 
       TLehrer  =record(TPerson)      {Subklasse, Typerweiterung von TPerson}
                  gehalt:real;
                 end;
    
  procedure (p:TPerson).lies;          {abstrakte Methode lies, muss }
    begin                              {überschrieben werden}
    end;
  procedure (p:TPerson).schreib;       {abstrakte Methode schreib}
    begin                              {muss überschrieben werden}
    end;
    
  procedure (p:TSchueler).lies;        {Methoden der Klasse TSchueler}
    begin
      write('Schüler:');readln(p.name);
      write('Stufe:');readln(p.stufe);
    end;
  procedure (p:TSchueler).schreib;
    begin
      writeln('Schüler:',p.name);
      writeln('  Stufe:',p.stufe);
    end; 
    
  procedure (p:TLehrer).lies;         {Methoden der Klasse TLehrer}
    begin
      write('Lehrer:');readln(p.name);
      write('Gehalt:');readln(p.gehalt);
    end;
  procedure (p:TLehrer).schreib;
    begin
      writeln('Lehrer:',p.name);
      writeln('  Gehalt:',p.Gehalt:0:2);
    end;  
    
  var s:TSchueler; l:TLehrer;             {Objekte s,l}
  
begin
  s.lies;l.lies;                         {Methodenaufrufe}     
  s.schreib;l.schreib;
end.

zum Start

{Vererbung, parent-Operator,
Methoden-Implementation unmittelbar
nach Vereinbarung der betreffenden Klasse}
 
program OOPDemo3;
  type TPerson  =record 
                   name:string 
                  end;
  procedure (p:TPerson).lies;
    begin
      write('Name:');readln(p.name);
    end;
  procedure (p:TPerson).schreib;
    begin
      writeln(p.name);
    end;
          
  type TSchueler=record(TPerson) 
                   stufe:integer;
                 end;
  procedure (p:TSchueler).lies;
    begin
      write('Schüler:');
      p.parent.lies;
      write('Stufe:');readln(p.stufe);
    end;
  procedure (p:TSchueler).schreib;
    begin
      p.parent.schreib;
      writeln('  Stufe:',p.stufe);
    end;
          
  type TLehrer  =record(TPerson)
                  gehalt:real;
                 end;            
  procedure (p:TLehrer).lies;
    begin
      write('Lehrer:');
      p.parent.lies;
      write('Gehalt:');readln(p.gehalt);
    end;
  procedure (p:TLehrer).schreib;
    begin
      p.parent.schreib;
      writeln('  Gehalt:',p.Gehalt:10:2);
    end;   
      
  type TRektor  =record(TLehrer)
                   zulage:real;
                 end;    
  procedure (p:TRektor).lies;
    begin
      write('Rektor:');
      p.parent.lies;
      write('Zulage:');readln(p.zulage);
    end;
  procedure (p:TRektor).schreib;
    begin
      p.parent.schreib;
      writeln('  Zulage:',p.zulage:10:2);
    end;
     
  var s:TSchueler;l:TLehrer;r:TRektor;
  
begin
  s.lies;l.lies;r.lies;
  s.schreib;l.schreib;r.schreib;
end.

zum Start

{Funktions-Methode (.lohn)
 Prozedur (schreibLohn)
 forward-Referenzen in Klassen-Vereinbarungen}
 
program OOPDemo4;
  type TPerson  =record 
                   name:string 
                 end;
       procedure (p:TPerson).lies; forward;
       procedure (p:TPerson).schreib; forward;
       function (p:TPerson).lohn:real; forward;
       
       procedure (p:TPerson).schreibLohn; forward;
       
  type TSchueler=record(TPerson) 
                   stufe:integer;
                 end;
       procedure (p:TSchueler).lies; forward;
       procedure (p:TSchueler).schreib; forward;
       
  type TLehrer  =record(TPerson)
                  gehalt:real;
                 end;
       procedure (p:TLehrer).lies; forward;
       procedure (p:TLehrer).schreib; forward;
       function (p:TLehrer).lohn:real; forward;               
       
  type TRektor  =record(TLehrer)
                   zulage:real;
                 end;
       procedure (p:TRektor).lies; forward;
       procedure (p:TRektor).schreib; forward;
       function (p:TRektor).lohn:real; forward;            
  
  
  procedure (p:TPerson).lies;
    begin
      write('Name:');readln(p.name);
    end;
  procedure (p:TPerson).schreib;
    begin
      writeln(p.name);
    end;
  function (p:TPerson).lohn:real;
    begin
      lohn:=0;
    end;
    
  procedure (p:TSchueler).lies;
    begin
      write('Schüler:');
      p.parent.lies;
      write('Stufe:');readln(p.stufe);
    end;
  procedure (p:TSchueler).schreib;
    begin
      p.parent.schreib;
      writeln('  Stufe:',p.stufe);
    end; 
    
  procedure (p:TLehrer).lies;
    begin
      write('Lehrer:');
      p.parent.lies;
      write('Gehalt:');readln(p.gehalt);
    end;
  procedure (p:TLehrer).schreib;
    begin
      p.parent.schreib;
      writeln('  Gehalt:',p.Gehalt:0:2);
    end;   
  function (p:TLehrer).lohn:real;
    begin
      lohn:=p.gehalt;
    end;
    
  procedure (p:TRektor).lies;
    begin
      write('Rektor:');
      p.parent.lies;
      write('Zulage:');readln(p.zulage);
    end;
  procedure (p:TRektor).schreib;
    begin
      p.parent.schreib;
      writeln('  Zulage:',p.zulage:0:2);
    end;   
  function (p:TRektor).lohn:real;
    begin
      lohn:=p.parent.lohn+p.zulage;
    end;
    
  procedure (p:TPerson).schreibLohn;
    begin
      writeln('Lohn von ',p.name,':',p.lohn:0:2);
    end;
    
  var s:TSchueler;l:TLehrer;r:TRektor;
  
begin
  s.lies;l.lies;r.lies;
  writeln;
  s.schreib;l.schreib;r.schreib;
  writeln;
  s.schreiblohn;l.schreiblohn;r.schreiblohn;
end.

zum Start

{Dynamische Objekte (Zeiger);
dynamische Bindung: array zur Speicherung mehrerer Personen,
hastype-Methode zur Feststellung des dynamischen Typs}
 
program OOPDemo5;
  type TPerson  =record 
                   name:string 
                 end;
  procedure (p:TPerson).lies;
    begin
      write('Name:');readln(p.name);
    end;
  procedure (p:TPerson).schreib;
    begin
      writeln(p.name);
    end;
          
  type TSchueler=record(TPerson) 
                   stufe:integer;
                 end;
  procedure (p:TSchueler).lies;
    begin
      write('Schüler:');
      p.parent.lies;
      write('Stufe:');readln(p.stufe);
    end;
  procedure (p:TSchueler).schreib;
    begin
      p.parent.schreib;
      writeln('  Stufe:',p.stufe);
    end;
          
  type TLehrer  =record(TPerson)
                  gehalt:real;
                 end;            
  procedure (p:TLehrer).lies;
    begin
      write('Lehrer:');
      p.parent.lies;
      write('Gehalt:');readln(p.gehalt);
    end;
  procedure (p:TLehrer).schreib;
    begin
      p.parent.schreib;
      writeln('  Gehalt:',p.Gehalt:10:2);
    end;   
 
      
 type  PPerson=^TPerson;                  {Zeigertypen auf  Objektklassen} 
       PSchueler=^TSchueler;
       PLehrer=^TLehrer;
  
  var  person:array[1..5] of PPerson;     {Zeiger-Tabelle (f.Lehrer & Schüler )}
       schueler:PSchueler;lehrer:PLehrer; {Zeiger auf Objekte}
       i:integer; wahl:integer;
  
begin
  for i:= 1 to 3 do
    begin
      write('Eingabe: 1=Schüler 2=Lehrer:');readln(wahl);
      if wahl=1 then
        begin new(schueler); person[i]:=schueler end
      else
        begin new(lehrer); person[i]:=lehrer end;
      person[i]^.lies;
    end;
    
  for i:= 1 to 3 do
    begin
      if person[i]^.hasType(TLehrer) then  {hasType(TLehrer)=true}
        writeln('Lehrer:')                  {falls person[i]^ vom}
      else                              {vom Typ TLehrer ist}
        writeln('Schüler:');
      person[i]^.schreib;
    end;
end.

zum Start