Herança e polimorfismo
A herança permite que uma classe reaproveite e especialize outra, e o polimorfismo permite que a mesma chamada de método se comporte de forma diferente conforme o tipo real do objeto em tempo de execução. Juntos, eles tornam o código extensível e expressivo.
Herança com extends
Uma classe herda de outra usando extends. A subclasse recebe todos os campos e métodos da superclasse e pode acrescentar os seus:
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;Aqui Cachorro herda o campo nome e o método descrever de Animal, e adiciona o campo raca.
Não existe inherited
O NeoObjectPascal não possui a palavra-chave inherited. Para reaproveitar o estado da superclasse, o construtor da subclasse atribui diretamente os campos herdados via self (como self.nome := n; acima). Não há chamada implícita ao construtor ou método do pai.
Métodos virtual e override
Para que uma subclasse possa substituir o comportamento de um método, a superclasse o declara como virtual e a subclasse o redefine com override, mantendo a mesma assinatura:
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;Cada subclasse define sua própria versão de emitirSom, substituindo a implementação de 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
Polimorfismo
O polimorfismo acontece quando uma mesma chamada de método produz comportamentos diferentes de acordo com o tipo real do objeto. A implementação executada é escolhida em tempo de execução — não pelo tipo declarado da variável.
No exemplo a seguir, Forma define métodos virtual que servem de base, e cada subclasse os redefine com override:
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
Repare em dois detalhes importantes:
Quadradoherda deRetangulo, que por sua vez herda deForma— a herança pode ter vários níveis.Quadradoredefine apenasdescrever, mas reaproveita ocalcularAreadeRetangulo. É por isso que um quadrado de lado 7 calcula corretamente a área 49.
Programe pensando na superclasse
Quando você trabalha com uma coleção de Forma, pode chamar calcularArea() em qualquer elemento sem saber se é um Retangulo ou um Quadrado. Cada objeto responde com a sua própria implementação — essa é a essência do polimorfismo.
Herança fixa uma hierarquia de classes; interfaces permitem compartilhar um contrato entre classes sem relação de parentesco. Siga para Interfaces.