Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Ereditarietà

Conoscere il meccanismo dell'ereditarietà tra classi, imparando ad implementarlo nel linguaggio Swift per programmare app mobile per iOS.
Conoscere il meccanismo dell'ereditarietà tra classi, imparando ad implementarlo nel linguaggio Swift per programmare app mobile per iOS.
Link copiato negli appunti

Dopo avere introdotto i concetti di base della programmazione orientata agli oggetti, come la definizione di una classe e la creazione di istanze, vediamo come possiamo implementare il meccanismo di ereditarietà delle classi in Swift.

In maniera analoga ad altri linguaggi moderni di programmazione, è possibile costruire nuove classi a partire da classi esistenti, in modo tale che la nuova possa "specializzare" o "estendere" la classe di partenza. Si fa riferimento alla classe base come superclasse o "classe padre", mentre quella creata a partire da essa è definita sottoclasse, "classe figlia" o "classe derivata". Le sottoclassi possono a loro volta essere utilizzate come classi padre per nuove sottoclassi. Una classe padre può dare origine a più sottoclassi, ma non viceversa: una sottoclasse può ereditare al più da una superclasse (il che, in altre parole, significa che Swift non supporta l'ereditarierà multipla).

Facciamo un esempio, considerando nuovamente la classe Persona:

class Persona {
    let nome: String
    let cognome: String
    var residenza: String
    init(nome: String, cognome: String, residenza: String) {
        self.nome = nome
        self.cognome = cognome
        self.residenza = residenza
    }
    func descrizione() {
        print("\(nome) \(cognome) di \(residenza)")
    }
}

La classe Persona ha 3 proprietà e un metodo, nonchè un inizializzatore (tratteremo approfonditamente questo argomento nella prossima lezione).

Definiamo adesso una sottoclasse di Persona, che permette di specializzarne le istanze con nuove proprietà. In particolare, creaiamo la classe figlia Studente che eredita le 3 proprietà e il metodo di Persona, aggiungendo due nuove proprietà: matricola e corso:

class Studente: Persona {
    let matricola: Int
    var corso: String
    init(nome: String, cognome: String, residenza: String, matricola: Int, corso: String) {
        self.corso = corso
        self.matricola = matricola
        super.init(nome: nome, cognome: cognome, residenza: residenza)
    }

La sintassi per definire una sottoclasse richiede l'indicazione della classe padre subito dopo il nome delle nuova sottoclasse, separata da due punti.

Se creiamo un'istanza della classe Studente:

var s = Studente(nome: "Antonio", cognome: "Calanducci", residenza: "Milano", matricola: 123456, corso: "Economia")

oltre ad accedere alle proprietà di Studente, potremmo anche interagire con le proprietà nome, cognome, residenza e chiamare il metodo descrizione() sull'istanza di Studente:

s.residenza = "Catania"
s.descrizione()
// Output: Antonio Calanducci di Catania

Override di metodi

A volte può essere necessario riscrivere (o fare un override di) un metodo di una sottoclasse affinchè abbia un comportamento diverso rispetto a quello della classe padre.

In Swift, non basta semplicemente, ridefinire il metodo all'interno della classe derivata, ma è necessario marcare esplicitamente la definizione del nuovo metodo con la parola riservata override.

Supponiamo ad esempio di voler riscrivere il metodo descrizione() della sottoclasse Studente in modo che questo stampi, oltre nome e cognome, anche la sua matricola e il corso a cui è iscritto.

La definizione della classe Studente diventa:

class Studente: Persona {
    let matricola: Int
    var corso: String
    init(nome: String, cognome: String, residenza: String, matricola: Int, corso: String ) {
        self.corso = corso
        self.matricola = matricola
        super.init(nome: nome, cognome: cognome, residenza: residenza)
    }
    override func descrizione() {
        print("Lo studente \(nome) \(cognome) è iscritto al corso di laurea in \(corso) con matricola \(matricola)")
    }
}

Se eseguiamo la seguente riga di codice:

s.descrizione()

Adesso il metodo descrizione() restituirà in output:

Lo studente Antonio Calanducci è iscritto al corso di laurea in Economia con matricola 123456

Tuttavia ci sono casi in cui, anziché riscrivere completamente un metodo di una superclasse, vogliamo estenderne le funzionalità. È possibile infatti far sì che il metodo sovrascritto esegua il codice dello stesso metodo definito nella classe padre, attraverso l'uso della parola riservata super. Quest'ultima ci permette di accedere a tutte le proprietà e a tutti i metodi della classe padre all'interno della classe figlia. Generalmente, la chiamata a super viene effettuata nel corpo del metodo esteso, insieme ad altre istruzioni.

Vediamo come estendere il metodo descrizione in modo che oltre a stampare le informazioni universitarie dello studente ci restituisca anche le informazioni generiche dell'istanza, come ad esempio la residenza. Basta aggiungere un'invocazione a super.descrizione() dentro il corpo del metodo riscritto in Studente:

override func descrizione() {
        print("Lo studente \(nome) \(cognome) è iscritto al corso di laurea in \(corso) con matricola \(matricola)")
        super.descrizione()
    }

Il lettore attento avrà notato che in verità avevamo utilizzato già questo meccanismo per invocare l'inizializzatore della classe Persona nell'inizializzatore della classe Studente:

super.init(nome: nome, cognome: cognome, residenza: residenza)

L'unica differenza da ricordare è che, nel caso degli inizializzatori, l'inizializzatore della superclasse va eseguita dopo aver inizializzato localmente le altre proprietà locali.

Esamineremo in maniera più dettagliata inizializzatori e deinizializzatori nel prossimo articolo.

Ti consigliamo anche