Vererbung und Polymorphie
Die Vererbung ermöglicht es einer Klasse, eine andere wiederzuverwenden und zu spezialisieren, und die Polymorphie ermöglicht es, dass sich derselbe Methodenaufruf je nach dem tatsächlichen Typ des Objekts zur Laufzeit unterschiedlich verhält. Zusammen machen sie den Code erweiterbar und ausdrucksstark.
Vererbung mit extends
Eine Klasse erbt von einer anderen mit extends. Die Unterklasse erhält alle Felder und Methoden der Oberklasse und kann ihre eigenen hinzufügen:
class Animal
var nome: String;
constructor Create(n: String)
begin
self.nome := n;
end;
public function descrever(): String
begin
return "Sou um animal chamado " + self.nome;
end;
end;
class Cachorro extends Animal
var raca: String;
constructor Create(n: String, r: String)
begin
self.nome := n;
self.raca := r;
end;
end;Hier erbt Cachorro das Feld nome und die Methode descrever von Animal und fügt das Feld raca hinzu.
Es gibt kein inherited
NeoObjectPascal besitzt nicht das Schlüsselwort inherited. Um den Zustand der Oberklasse wiederzuverwenden, weist der Konstruktor der Unterklasse die geerbten Felder direkt über self zu (wie self.nome := n; oben). Es gibt keinen impliziten Aufruf des Konstruktors oder der Methode der Elternklasse.
virtual- und override-Methoden
Damit eine Unterklasse das Verhalten einer Methode ersetzen kann, deklariert die Oberklasse sie als virtual und die Unterklasse definiert sie mit override neu, wobei dieselbe Signatur beibehalten wird:
class Animal
var nome: String;
constructor Create(n: String)
begin
self.nome := n;
end;
public virtual function emitirSom(): String
begin
return "Som genérico";
end;
end;
class Cachorro extends Animal
var raca: String;
constructor Create(n: String, r: String)
begin
self.nome := n;
self.raca := r;
end;
public override function emitirSom(): String
begin
return "Au au! Meu nome é " + self.nome;
end;
end;
class Gato extends Animal
constructor Create(n: String)
begin
self.nome := n;
end;
public override function emitirSom(): String
begin
return "Miau! Eu sou " + self.nome;
end;
end;Jede Unterklasse definiert ihre eigene Version von emitirSom und ersetzt damit die Implementierung von Animal:
var animal: Animal;
var cachorro: Cachorro;
var gato: Gato;
begin
animal := new Animal("Animal Genérico");
WriteLn(animal.emitirSom());
cachorro := new Cachorro("Rex", "Labrador");
WriteLn(cachorro.emitirSom());
gato := new Gato("Mimi");
WriteLn(gato.emitirSom());
end.Som genérico Au au! Meu nome é Rex Miau! Eu sou Mimi
Polymorphie
Die Polymorphie tritt auf, wenn ein und derselbe Methodenaufruf je nach tatsächlichem Typ des Objekts unterschiedliches Verhalten erzeugt. Die ausgeführte Implementierung wird zur Laufzeit gewählt — nicht anhand des deklarierten Typs der Variable.
Im folgenden Beispiel definiert Forma virtual-Methoden, die als Basis dienen, und jede Unterklasse definiert sie mit override neu:
class Forma
public virtual function calcularArea(): Integer
begin
return 0;
end;
public virtual function descrever(): String
begin
return "Forma genérica";
end;
end;
class Retangulo extends Forma
var largura: Integer;
var altura: Integer;
constructor Create(l: Integer, a: Integer)
begin
self.largura := l;
self.altura := a;
end;
public override function calcularArea(): Integer
begin
return self.largura * self.altura;
end;
public override function descrever(): String
begin
return "Retângulo " + self.largura + "x" + self.altura;
end;
end;
class Quadrado extends Retangulo
constructor Create(lado: Integer)
begin
self.largura := lado;
self.altura := lado;
end;
public override function descrever(): String
begin
return "Quadrado " + self.largura + "x" + self.largura;
end;
end;
var forma: Forma;
var retangulo: Retangulo;
var quadrado: Quadrado;
begin
forma := new Forma();
WriteLn(forma.descrever(), " - Área: ", forma.calcularArea());
retangulo := new Retangulo(5, 10);
WriteLn(retangulo.descrever(), " - Área: ", retangulo.calcularArea());
quadrado := new Quadrado(7);
WriteLn(quadrado.descrever(), " - Área: ", quadrado.calcularArea());
end.Forma genérica - Área: 0 Retângulo 5x10 - Área: 50 Quadrado 7x7 - Área: 49
Beachten Sie zwei wichtige Details:
Quadradoerbt vonRetangulo, das wiederum vonFormaerbt — die Vererbung kann mehrere Ebenen haben.Quadradodefiniert nurdescreverneu, verwendet aber dascalcularAreavonRetangulowieder. Deshalb berechnet ein Quadrat mit Seitenlänge 7 korrekt die Fläche 49.
Programmieren Sie mit Blick auf die Oberklasse
Wenn Sie mit einer Sammlung von Forma arbeiten, können Sie calcularArea() auf jedem Element aufrufen, ohne zu wissen, ob es ein Retangulo oder ein Quadrado ist. Jedes Objekt antwortet mit seiner eigenen Implementierung — das ist die Essenz der Polymorphie.
Die Vererbung legt eine Klassenhierarchie fest; Schnittstellen ermöglichen es, einen Vertrag zwischen Klassen ohne Verwandtschaftsbeziehung zu teilen. Weiter zu Schnittstellen.