Mis à jour le vendredi 27 janvier 2017
  • 15 heures
  • Facile

Ce cours est visible gratuitement en ligne.

Ce cours existe en livre papier.

Ce cours existe en eBook.

Vous pouvez obtenir un certificat de réussite à l'issue de ce cours.

J'ai tout compris !

L'héritage

Connectez-vous ou inscrivez-vous pour bénéficier de toutes les fonctionnalités de ce cours !

L’héritage est un concept fort intéressant dans le monde de la programmation orientée objet. L’héritage permet d’utiliser des classes pour en construire de nouvelles. On pourra alors obtenir des classes plus complètes et plus précises. 

Comme dans la vie de tous les jours, vous pouvez trouver des objets différents, mais qui pour autant peuvent s’utiliser de la même façon. Par exemple : un scooter est une moto et une moto-cross est aussi une moto. On l’utilisera de la même façon pour rouler, pourtant ce sont bien deux motos différentes au final. On aura donc des attributs de base à fournir à nos objets scooter et moto-cross, mais on aura aussi des attributs spécifiques à chacune de ces motos (qui permettront de fournir la différence entre un scooter et une moto-cross).

Voyons comment appliquer cela à nos objets grâce à la notion d’héritage.

L’héritage

L’héritage, on peut en voir partout dans notre code. Pour être sûr de savoir quand réaliser un héritage, c’est très simple ! Il suffit de se poser une seule question, à savoir : « Est-ce que B est un A ? », sachant que A et B sont deux objets différents. Si à cette question vous répondez « oui », alors vous pouvez utiliser l’héritage. Autrement, l’héritage n’aura tout simplement aucun sens !

Pour que vous puissiez mieux vous rendre compte, voici quelques exemples  faciles à comprendre :

  • Une voiture est un véhicule.

  • Une moto est un véhicule.

  • Un chien est un animal.

  • Un chat est un animal.

  • etc.

Pour ces exemples, on dira queVoiture hérite deVéhicule ou encore queChat hérite deAnimal.Voiture etChat sont deux classes qu’on appellera classes héritées.Véhicule etAnimal eux seront des classes qu’on appellera classes mères ou encore classes parentes.

Le principe de l’héritage est infini. Par exemple, prenons un chien : il existe plusieurs races de chien comme le labrador. Un labrador est un chien, un chien est un animal.

Réaliser un héritage

Mettons nous à la pratique et voyons comment utiliser l’héritage en Swift. Pour dire qu’une classe hérite d’une autre classe, on va utiliser le signe:. Ce signe permettra de dire « hérite de ». Reprenons notre classe du chapitre précédent :Personne. On va créer une nouvelle classeActeur. Pour cela, n’oubliez pas de créer un nouveau fichier. Un acteur est une personne. Donc, on peut procéder à l’héritage. 

class Acteur : Personne {  

}

Acteur hérite donc maintenant dePersonne, c’est-à-dire qu’il hérite de tous ses attributs et de toutes ses méthodes. On obtient là, rien qu’avec ce code, une classe complètement identique àPersonne. Pour en avoir le cœur net, essayez ce code et voyez par vous-mêmes :

let personne = Personne(nom: "Dupont", prenom: "Jean", sexe: "m", age: 20, adresse: "94 rue machin")
let acteur = Acteur(nom: "Dupont", prenom: "Jean", sexe: "m", age: 20, adresse: "94 rue machin")

personne.affiche()
acteur.affiche()

Vous voyez qu’on se sert de l’objetActeur de la même façon que de l’objet Personne. C’est normal, parce qu’un acteur est une personne. Vous pouvez donc utiliser les méthodes et attributs de l’objetPersonne avec l’objetActeur.

Ça a l’air cool ton truc là, mais c’est pas un peu inutile ?

Vu comme ça, bien sûr que si ! Sauf que, grâce à cette méthode, toutes modifications effectuées à la classePersonne seront répercutées pour la classeActeur. Et grâce à cette méthode encore, on pourra attribuer nos attributs et méthodes spécifiques pour notre classe Acteur.

Qu’est-ce qu’un acteur a de spécifique par rapport à une personne normale ? Il joue par exemple dans un ou plusieurs films, ce qui n’est pas forcément le cas pour une personne en général. On va pouvoir lui préciser un attribut qui permettra de savoir les films dans lesquels il a joué. Un acteur pourra auss jouer dans un film, participer à un casting pour un film, etc. Traduisons tout cela en code maintenant :

class Acteur : Personne {
   
   var filmsJoues: [String] = [] // Par défaut, le tableau est vide

    func jouerUnRole(nomDuFilm: String) {

    }

    func participerAUnCasting(nomSociete: String) {

    }
}

Avec ça, non seulementActeur aura les mêmes caractéristiques quePersonne, mais il aura en plus un nouvel attribut et deux nouvelles méthodes ! 

Remarquez dans cette exemple que pour les films joués, j’ai indiqué cela par un tableau qui ne comportera que le nom des films dans lesquels il a joué. Vous auriez très bien pu créer une classeFilm qui caractériserait un film (nom, date de sortie, etc.) et de ce fait, indiquer que le tableau comportera non plus des éléments de typeString mais de typeFilm. De même, on peut aussi caractériser une société. Je ne vais pas réaliser les classes pour l’exemple, mais vous pouvez le faire si vous le souhaitez. On obtiendrait ceci : 

class Acteur : Personne {

    var filmsJoues: [Film] = [] // Par défaut, le tableau est vide

    func jouerUnRole(film: Film) {

    }

    func participerAUnCasting(societe: Societe) {

    }
}

Dans notre fichier main.swift, on peut donc maintenant s’amuser avec nos objetsPersonne etActeur.

let personne = Personne(nom: "Dupont", prenom: "Jean", sexe: "m", age: 20, adresse: "94 rue machin")
let acteur = Acteur(nom: "Nicolas", prenom: "Duval", sexe: "m", age: 46, adresse: "19 rue bidule")

// Comme Acteur hérite de Personne, on aurait pu préciser le type de acteur de deux façons
// let acteur: Acteur
// let acteur: Personne
// Les deux marchent. De cette façon, une méthode qui prend une
// personne de type Personne en paramètre, peut en fait prendre
// aussi un acteur de type Acteur ou un autre type de personne
// qui hérite de Personne.

personne.feterSonAnniversaire()
acteur.jouerUnRole(nomDuFilm: "Titre du film le plus cool au monde !")
acteur.participerAUnCasting(nomSociete: "Nom d'une société qui réalise des films")

let listeDeFilmsDeNicolasDuval = acteur.filmsJoues

Le polymorphisme

La notion d’héritage, ça ne s’arrête pas là ! Pour un objet, vous pouvez avoir le même comportement ou alors… presque le même. Vous pouvez réaliser ce qu’on appelle le polymorphisme ou encore overriding en anglais. On va modifier la méthode de la classe parente ou même tout simplement la redéfinir.

Reprenons nos objetsPersonne etActeur. On souhaite maintenant que si un acteur fête son anniversaire, non seulement son âge augmente de un, mais qu’aussi, il l’annonce à tout le monde ! On a donc besoin dans ce cas-là d’une part, de réaliser la même action que pour une personne normale, mais d’autre part d’annoncer à tout le monde son anniversaire.

Pour cela, nous n’allons pas réécrire la même méthode que celle pourPersonne, mais on va dire d’exécuter la même méthode quePersonne. Il existe un mot-clé supplémentaire qui vous permettra d’accéder aux attributs et méthodes de votre classe mère, ce mot-clé est :super.super représentera donc dans votre classeActeur, la classePersonne. Vous pourrez grâce à ce mot-clé, réaliser les actions dePersonne dans votre classeActeur

Une dernière chose, il faudra préciser que vous réécrivez une fonction déjà existante dans la classe mère. Pour cela, on écrira le mot-cléoverride avant la définition de la fonction.

class Acteur : Personne {

    // ...
    
    override func feterSonAnniversaire() {
        super.feterSonAnniversaire()
        print("Aujourd'hui c'est l'anniversaire de " + self.nom + ". Vous êtes tous invités !")
    }

    override func affiche() {
        print("Nom, prénom de l'acteur " + self.nom + ", " + self.prenom)
    }
}

Que s’est-il passé ici ? 

Dans la méthodefeterSonAnniversaire() : nous avons décidé dans un premier temps de réaliser exactement la même chose que l’on avait écrit pour la classePersonne. Pour cela, on a utilisé le mot-clésuper qui permet de s’adresser à la classe mère (à savoir iciPersonne). Nous l’avons utilisé comme si nous utilisions un objet. Ainsi,super.feterSonAnniversaire() a réalisé l’action d’ajouter +1 à l’âge de l’acteur. Seulement, dans notre méthode réécrite pour la classeActeur, nous ne voulons pas seulement réaliser la même action que pourPersonne, on souhaite également prévenir tout le monde. On ajoute alors à la suite notreprint(). Notez que puisque Acteur hérite dePersonne, alors on peut récupérer les attributs de l’objetPersonne dans notre classeActeur avec le mot-cléself. Même si les attributs ne sont pas écrits explicitement dans la classeActeur, Swift le sait. ;) 

Pour la méthodeaffiche(), on n’utilise pas le mot-clésuper. Cela veut  donc dire qu’on a décidé de complètement réécrire la méthode. Ici, dans l’exemple, on veut juste afficher le nom et prénom de l’acteur et c’est tout.

Vous pouvez maintenant essayer de jouer à nouveaux avec vos objets et voir les comportements de ces derniers. 

let personne = Personne(nom: "Dupont", prenom: "Jean", sexe: "m", age: 20, adresse: "94 rue machin")
let acteur = Acteur(nom: "Duval", prenom: "Nicolas", sexe: "m", age: 46, adresse: "19 rue bidule")

personne.feterSonAnniversaire()
personne.affiche()

acteur.feterSonAnniversaire()
acteur.affiche()

On réalise les mêmes actions, et pourtant, on n'obtient pas la même chose en sortie sur la console. Voilà toute la puissance de l’héritage et surtout du polymorphisme. :)

class Acteur : Personne {
    var filmsJoues: [String]
    
    init(nom: String, prenom: String, sexe: String, age: Int, adresse: String, filmsJoues: [String]) {
        self.filmsJoues = filmsJoues
        super.init(nom: nom, prenom: prenom, sexe: sexe, age: age, adresse: adresse)
    }
}

Pour résumer

  • On peut réaliser un héritage si l’on peut dire que « B est un A », B et A étant deux classes différentes.

  • Une classe B qui hérite d’une autre classe A possédera tous les attributs et méthodes de A.

  • Une classe héritée peut avoir des attributs et méthodes supplémentaires que ceux de sa classe mère.

  • On peut faire hériter une classe qui est déjà héritée (et ainsi de suite) mais on ne peut faire hériter deux classes à une même classe.

  • Il est possible grâce au polymorphisme de redéfinir ou modifier le comportement d’une méthode.

Exemple de certificat de réussite
Exemple de certificat de réussite