Fehlermeldung ... Zugriff auf (k as PKW).tueren Der "as" Operator dient zur Typanpassung innerhalb von Klassenhierarchien. "k as PKW" ist vom Typ "PKW" Die Typanpassung kann fehlschlagen (Laufzeitfehler)."> Fehlermeldung ... Zugriff auf (k as PKW).tueren Der "as" Operator dient zur Typanpassung innerhalb von Klassenhierarchien. "k as PKW" ist vom Typ "PKW" Die Typanpassung kann fehlschlagen (Laufzeitfehler).">
Präsentation herunterladen
1
Unter- und Oberklassen: Beispiel
type KFZ = class kennzeichen: String; ... end; PKW = class(KFZ) tueren: integer end; LKW = class(KFZ) nutzlast: integer end; ... var k: KFZ; p: PKW; ... p := PKW.Create; p.kennzeichen := "DD-XX 1"; p.tueren := 5; k := p; ... Zugriff auf k.kennzeichen ... Jeder PKW ist ein KFZ: Die Zuweisung eines Objekts der Unterklasse an eine Variable der Oberklasse ist zulässig. Bei der Zuweisung gehen keinerlei Informationen verloren, das Objekt bleibt unverändert.
2
Typanpassung type KFZ = class kennzeichen: String; ... end; PKW = class(KFZ) tueren: integer end; LKW = class(KFZ) nutzlast: integer end; ... var k: KFZ; p: PKW; ... p := PKW.Create; p.kennzeichen := "DD-XX 1"; p.tueren := 5; k := p; ... ... Zugriff auf k.tueren ... ->Fehlermeldung ... Zugriff auf (k as PKW).tueren Der "as" Operator dient zur Typanpassung innerhalb von Klassenhierarchien. "k as PKW" ist vom Typ "PKW" Die Typanpassung kann fehlschlagen (Laufzeitfehler).
3
Regeln zur Typanpassung
Jedes Objekt hat immer eine eindeutige Klassenzugehörigkeit, die sich von der Erzeugung bis zur Löschung nicht ändert. Einer Variable von einem Klassentyp K können Objekte der Klasse K und jeder Unterklasse von K zugewiesen werden. Der Zugriff auf ein Datenfeld, eine Methode oder eine Eigenschaft eines Objekts o ist nur möglich, wenn dies in der Klassendefinition der Klasse von o vorgesehen ist. Wenn ein Objekt o1 von einer Unterklasse K1 einer Klasse K ist, aber über eine Variable der Klasse K zugänglich ist, so kann o1 mittels des "as"-Operators (o1 as K1) auch wie ein Objekt der Klasse K1 behandelt werden ("Typanpassung", "down-cast"). Seien K1 und K2 verschiedene Unterklassen von K, o1 ein Objekt der Klasse K1, das über eine Variable der Klasse K zugänglich ist. Die Typanpassung "o1 as K2" führt zu einem Laufzeitfehler. Ein Test, ob ein Objekt o einer Klasse K zur Unterklasse K1 gehört, ist mit "o is K1" möglich.
4
Frühe und späte Bindung
Frühe Bindung: Im allgemeinen wird die bei Eintreffen einer bestimmten Nachricht aufzurufende Methode bereits zur Übersetzungszeit, abhängig von der Klassenzugehörigkeit des angesprochenen Objekts, bestimmt. Späte Bindung: In manchen Fällen ist zur Übersetzungszeit nur eine Oberklasse des zur Laufzeit angesprochenen Objekts bekannt. In diesem Fall kann man die Wahl der aufzurufenden Methode von der erst zur Laufzeit bekannten Unterklasse abhängig machen. Späte Bindung in Object Pascal: "virtuelle Methoden", Schlüsselworte virtual und dynamic (Unterschied zwischen virtual/dynamic nur in Optimierungen.) Deklaration von Methoden, die virtuelle Methoden (in Unterklassen) "überdefinieren": Schlüsselwort override Implementierung: Virtual Method Table (VMT)
5
Polymorphie von Methoden (1)
type KFZ = class kennzeichen: String; procedure anmelden(k: KFZDaten); virtual; end; PKW = class(KFZ) tueren: integer procedure anmelden(k: KFZDaten); override; end; LKW = class(KFZ) nutzlast: integer procedure anmelden(k: KFZDaten); override; var k: KFZ; p: PKW; ... p := PKW.Create; ... p.kennzeichen := "DD-XX 1"; p.tueren := 5; k := p; k.anmelden(...);
6
Polymorphie von Methoden (2)
gleicher Methodenname in Ober- und Unterklasse semantische Ähnlichkeit (!) der Methodenrümpfe dynamische Auswahl der Implementierung Prinzip: TObject Methoden- Vererbung Operationen- Suche zur Laufzeit nach der speziellsten Version ("dynamisches Binden") KFZ PKW
7
TObject Alle Klassen in Object Pascal sind implizit von der Basisklasse TObject abgeleitet. Ungefähre Struktur: TObject = class constructor Create; // Speicherplatzreservierung // Festlegung der Adresse (Identität) procedure Free; //Aufruf von Destroy //falls Adresse ≠ nil destructor Destroy; virtual; end;
8
Konstruktoren für Unterklassen
Möglichkeit 1: Standardkonstruktor (aus TObject) verwenden. var obj: K; obj := K.Create; Möglichkeit 2: Eigener Konstruktor. type K = class(K0) var X, Y: integer; constructor Create(Xinit,Yinit: integer); end; constructor K.Create(Xinit,Yinit : integer); begin inherited Create; X := Xinit; Y := Yinit; end; var obj: K; obj := K.Create(10,20); Möglichkeit 3: Standardkonstruktor (aus TObject) verwenden und eigene Initialisierungsprozedur ("Init").
9
Destruktoren für Unterklassen
type K = class(K0) var X, Y: integer; constructor Create(Xinit,Yinit: integer); destructor Destroy; override; end; Regeln für Destruktoren: Immer indirekt über Free aufrufen (vermeidet Laufzeitfehler) Im Rumpf immer als letzte Aktion Destruktor der Oberklasse aufrufen. destructor K.Destroy(Xinit,Yinit : integer); begin inherited Destroy; end;
10
Beispiel: Bauteileverwaltung
Jedes Bauteil hat eine Bauteilnummer (Zeichenreihe) und einen Preis (Ganzzahl). Bauteile können Elemente und Baugruppen sein. Eine Baugruppe besteht aus mehreren Bauteilen. Für ein Element ist der Preis direkt festgelegt, für Baugruppen berechnet er sich aus der Summe der Preise der enthaltenen Bauteile.
11
Klassenstruktur für Bauteile-Beispiel (1)
type TBauteil = class bauteilNr: string; function gibPreis: integer; virtual; end; TElement = class(TBauteil) preis: integer; constructor Create(n: string; p: integer); function gibPreis: integer; override; TBaugruppe = class(TBauteil) bauteile: array of TBauteil; constructor Create(n: string); procedure bauteilHinzu (b: TBauteil); function gibAnzahl: integer;
12
Abstrakte Methoden Methoden, für die keine Implementierung gegeben werden kann, sondern die ausschließlich als Platzhalter für speziellere Implementierungen dienen, werden "abstrakt" genannt. Schlüsselwort "abstract" Klassen, die abstrakte Methoden enthalten, heißen auch "abstrakte Klassen". Beispiel: Was ist die Implementierung der Methode "gibPreis" für die Oberklasse TBauteil? type TBauteil = class bauteilNr: string; function gibPreis: integer; virtual; abstract; end;
13
Sichtbarkeit Öffentlich = public Privat = private
Sichtbar in der aktuellen Unit Nur für Unterklassen = protected Auch sichtbar in Unterklassen in einer anderen Unit Geheimnisprinzip: Grundsätzlich sollte so viel wie möglich der in einem Objekt gespeicherten Information als "privat" deklariert werden. Erhöhung der Wartungsfreundlichkeit und Stabilität.
14
Klassenstruktur für Bauteile-Beispiel (2)
type TBauteil = class public bauteilNr: string; function gibPreis: integer; virtual; abstract; end; TElement = class(TBauteil) private preis: integer; constructor Create(n: string; p: integer); function gibPreis: integer; override; TBaugruppe = class(TBauteil) bauteile: array of TBauteil; constructor Create(n: string); procedure bauteilHinzu (b: TBauteil); function gibAnzahl: integer;
15
Implementierung Bauteile-Beispiel (1)
constructor TElement.Create(n: string; p: integer); begin bauteilNr := n; preis := p; end; function TElement.gibPreis: integer; gibPreis := preis; constructor TBaugruppe.Create(n: string); procedure TBaugruppe.bauteilHinzu(b: TBauteil); SetLength(bauteile,Length(bauteile)+1); bauteile[High(bauteile)] := b;
16
Implementierung Bauteile-Beispiel (2)
function TBaugruppe.gibPreis: integer; var i,p: integer; begin p := 0; for i:=0 to High(bauteile) do p := p + bauteile[i].gibPreis; gibPreis := p; end; function TBaugruppe.gibAnzahl: integer; var i,a: integer; a := 0; if bauteile[i] is TBaugruppe then a := a + (bauteile[i] as TBaugruppe).gibAnzahl else a := a+1; gibAnzahl := a;
17
Schichten-Architektur
Benutzungsoberfläche Bauteile_U.pas Fachliches Modell Bauteile_Modell.pas
18
Auszug aus "Bauteile_U.pas"
procedure TForm1.AbfrageClick(Sender: TObject); var bauteilNr: string; b: TBauteil; begin if BauteilListBox1.ItemIndex <> -1 then begin bauteilNr := BauteilListBox1.items [BauTeilListBox1.ItemIndex]; b := findeBauteil(bauteilNr); BauteilPreis.Text := IntToStr(b.gibPreis); if b is TElement then BauteilAnzahl.Text := '(keine)' else BauteilAnzahl.Text := IntToStr((b as TBaugruppe).gibAnzahl); end end;
Ähnliche Präsentationen
© 2025 SlidePlayer.org Inc.
All rights reserved.