A herdanza permite crear unha clase a partir doutra. Usamos extends: a clase orixinal é a superclase e a nova é a subclase.
Un profesor é unha persoa. Pode herdar datos e métodos de Persoa e engadir outros propios.
🧬 extends e a chamada ao construtor con super
class Persoa {
final String nome;
Persoa(this.nome);
void saudar() {
print('Ola, son $nome.');
}
}
class Profesor extends Persoa {
// A superclase necesita un nome: pasámosllo con super(nome).
Profesor(String nome) : super(nome);
void explicar() {
print('$nome explica Dart.'); // nome é un atributo herdado
}
}
void main() {
var profesor = Profesor('Diego Rodicio');
profesor.saudar(); // Método herdado
profesor.explicar(); // Método propio
}
Os construtores non se herdan. Se non escribimos unha chamada ao da superclase, Dart intenta chamar a super() sen argumentos. Se ese construtor necesita datos, debemos pasalos.
✂️ A forma curta: parámetros super
Podemos evitar repetir un parámetro que só se pasa á superclase. Por exemplo, Profesor(String nome) : super(nome); pode escribirse Profesor(super.nome);.
Tamén funciona cos parámetros nomeados:
class Persoa {
final String nome;
Persoa({required this.nome});
}
class Profesor extends Persoa {
// Recibe nome e pásallo ao construtor de Persoa.
Profesor({required super.nome});
}
void main() {
var profesor = Profesor(nome: 'Diego Rodicio');
print(profesor.nome);
}
📱 Esta é a idea que hai detrás de
super.keyen Flutter: recibir un parámetro e pasalo ao construtor da superclase. O significado dekeyverémolo en Flutter.
🔁 Sobrescribir un método e usar super.metodo()
Sobrescribir é dar a nosa propia versión dun método herdado. Engadimos @override para indicar a intención; o analizador avísanos se non existe un membro que sobrescribir.
Se queremos conservar o comportamento anterior e engadir algo, podemos chamar a super.metodo(). Non é obrigatorio en todos os métodos: depende do que queiramos facer e do contrato da superclase.
🧪 Exemplo completo: ampliar un saúdo
🔗 Ver o código en DartPad — https://dartpad.dev/?id=ece7d59f9e194522395fca282ea9e74a
En Flutter tamén sobrescribiremos métodos e atoparemos chamadas como super.initState() e super.dispose(). Alí veremos cando se executan e a orde que debemos respectar.
🧩 Clases e métodos abstractos
Unha clase abstract serve de base e non se pode instanciar directamente. Pode deixar métodos sen corpo para que os completen as subclases concretas.
abstract class PersoaCentro {
// Método abstracto: remata en ; porque aínda non ten implementación.
void presentarse();
}
class Profesor extends PersoaCentro {
@override
void presentarse() {
print('Son Diego Rodicio, profesor no IES San Mamede.');
}
}
void main() {
PersoaCentro persoa = Profesor();
persoa.presentarse();
// PersoaCentro(); // ❌ Non podemos instanciar a clase abstracta
}
Unha clase abstracta tamén pode ter atributos, construtores e métodos xa implementados. Verémolo no exemplo final.
🤝 implements: cumprir un contrato
Con extends herdamos implementación. Con implements comprometémonos a ofrecer os membros de instancia da interface, pero non herdamos o código que os implementa.
abstract class Presentable {
void presentarse();
}
class Profesor implements Presentable {
// Temos que proporcionar o método que esixe o contrato.
@override
void presentarse() {
print('Son Diego Rodicio.');
}
}
void main() {
Presentable profesor = Profesor();
profesor.presentarse();
}
Toda clase define unha interface, aínda que non leve a palabra interface. Aquí usamos unha clase abstracta para que o contrato sexa fácil de ver. Os construtores e membros estáticos non forman parte dese contrato.
🔎 Recordatorio: herdanza con tipos xenéricos
No Tema 2.1 vimos tipos como List<String>. As clases das que herdamos tamén poden recibir un tipo. En Flutter leremos extends State<MeuWidget>: é a clase State parametrizada co tipo MeuWidget. Non é outra forma distinta de herdanza.
🔗 Herdanza e sobrescritura — https://dart.dev/language/extend · Interfaces implícitas — https://dart.dev/language/classes#implicit-interfaces