Leçon 4/6 10 min

L'héritage : réutiliser sans copier

Une classe « est un » cas spécialisé d'une autre : elle hérite de tout son parent et ajoute le sien. Puissant, mais à manier avec prudence. Avec une démo interactive.

FR EN

Le problème : presque la même chose, mais pas tout à fait

Tu as une classe Compte solide. Maintenant on te demande un compte épargne : exactement comme un compte (déposer, retirer, un solde protégé), plus un taux d'intérêt. Vas-tu copier-coller tout le code de Compte pour y ajouter trois lignes ? Surtout pas : le jour où tu corriges un bug dans Compte, tu devras le corriger deux fois, et tu oublieras.

Il te faut dire : « un CompteEpargne, c'est un Compte, avec quelque chose en plus ». C'est exactement ce que permet l'héritage.

L'idée : une classe parente, une classe enfant

Une classe enfant peut hériter d'une classe parente : elle récupère automatiquement toutes ses propriétés et méthodes, puis elle en ajoute (ou en redéfinit). On dit que l'enfant « est un » parent : un CompteEpargne est un Compte.

  • Classe parente (ou mère, super-classe) : le cas général. Ici Compte.
  • Classe enfant (ou fille, sous-classe) : le cas spécialisé. Ici CompteEpargne, qui étend (extends) Compte.
  • L'enfant réutilise le parent gratuitement, et n'écrit que ce qui change.
La classe parente Compte (déposer, retirer) est héritée par deux classes enfants : CompteEpargne qui ajoute les intérêts, et CompteCourant qui ajoute le découvert. Compte deposer() · retirer() hérite de CompteEpargne hérite deposer/retirer + ajouterInterets() CompteCourant hérite deposer/retirer + découvert autorisé Chaque enfant récupère tout le parent, et n'ajoute que sa spécificité.
Un seul parent, des enfants spécialisés : on écrit le commun une fois dans Compte.

En code : extends et super

L'enfant étend le parent. Dans son constructeur, super(...) appelle d'abord le constructeur du parent (pour mettre en place la partie héritée), puis l'enfant ajoute la sienne.

classe Compte:
    privé solde = 0
    public deposer(m): si m > 0: this.solde += m
    public retirer(m): si 0 < m <= this.solde: this.solde -= m

// CompteEpargne EST UN Compte, avec un taux en plus
classe CompteEpargne hérite de Compte:
    privé taux
    constructeur(taux):
        super()              // construit la partie "Compte"
        this.taux = taux
    public ajouterInterets():
        this.deposer(this.solde * this.taux)   // réutilise deposer() du parent

epargne = new CompteEpargne(0.05)
epargne.deposer(1000)        // méthode HÉRITÉE de Compte
epargne.ajouterInterets()    // méthode PROPRE → +50

ajouterInterets() ne réécrit pas le dépôt : il appelle la méthode héritée deposer(). Tout le code commun reste à un seul endroit, dans Compte.

L'héritage en vrai (essaie)

Voici un vrai CompteEpargne extends Compte en JavaScript. Le bouton vert utilise une méthode héritée de Compte ; le bouton violet utilise la méthode propre à l'enfant.

epargne.solde 0 €

Puissant… mais à manier avec prudence

L'héritage est séduisant, et c'est justement le piège. En liant fort l'enfant au parent, il crée une dépendance rigide : changer le parent peut casser tous les enfants. Et les hiérarchies profondes (un enfant d'un enfant d'un enfant…) deviennent vite illisibles.

Le réflexe du débutant est d'utiliser l'héritage partout (« un chat hérite d'animal qui hérite de… »). C'est l'erreur la plus courante en POO. Avant d'hériter, pose-toi la vraie question : est-ce un « est un » (héritage) ou un « a un » (composition) ? La prochaine leçon te donne le bon réflexe.

Prochaine étape

L'héritage dit « est un ». Mais souvent, ce que tu veux dire, c'est « a un » : une voiture a un moteur, elle n'est pas un moteur. C'est la composition, et c'est le réflexe que préfèrent les pros.

Leçon 5 : composition vs héritage →

The problem: almost the same, but not quite

You have a solid Compte class. Now you're asked for a savings account: exactly like an account (deposit, withdraw, a protected balance), plus an interest rate. Are you going to copy-paste all of Compte's code to add three lines? Definitely not: the day you fix a bug in Compte, you'd have to fix it twice, and you'll forget.

You need to say: "a CompteEpargne is a Compte, with something extra". That's exactly what inheritance allows.

The idea: a parent class, a child class

A child class can inherit from a parent class: it automatically gets all its properties and methods, then adds (or overrides) some. We say the child "is a" parent: a CompteEpargne is a Compte.

  • Parent class (or superclass): the general case. Here Compte.
  • Child class (or subclass): the specialized case. Here CompteEpargne, which extends Compte.
  • The child reuses the parent for free, and writes only what changes.
The parent class Compte (deposit, withdraw) is inherited by two child classes: CompteEpargne which adds interest, and CompteCourant which adds overdraft. Compte deposer() · retirer() inherits CompteEpargne inherits deposit/withdraw + ajouterInterets() CompteCourant inherits deposit/withdraw + overdraft Each child gets the whole parent, and adds only its specialty.
One parent, specialized children: the common part is written once in Compte.

In code: extends and super

The child extends the parent. In its constructor, super(...) first calls the parent's constructor (to set up the inherited part), then the child adds its own.

class Compte:
    private solde = 0
    public deposer(m): if m > 0: this.solde += m
    public retirer(m): if 0 < m <= this.solde: this.solde -= m

// CompteEpargne IS A Compte, with an extra rate
class CompteEpargne extends Compte:
    private taux
    constructor(taux):
        super()              // builds the "Compte" part
        this.taux = taux
    public ajouterInterets():
        this.deposer(this.solde * this.taux)   // reuses the parent's deposer()

epargne = new CompteEpargne(0.05)
epargne.deposer(1000)        // method INHERITED from Compte
epargne.ajouterInterets()    // OWN method → +50

ajouterInterets() doesn't rewrite the deposit: it calls the inherited method deposer(). All the common code stays in one place, in Compte.

Inheritance for real (try it)

Here's a real CompteEpargne extends Compte in JavaScript. The green button uses a method inherited from Compte; the purple button uses the child's own method.

epargne.solde 0 €

Powerful… but handle with care

Inheritance is seductive, and that's precisely the trap. By tightly binding the child to the parent, it creates a rigid dependency: changing the parent can break every child. And deep hierarchies (a child of a child of a child…) quickly become unreadable.

The beginner reflex is to use inheritance everywhere ("a cat inherits from animal which inherits from…"). It's the most common mistake in OOP. Before inheriting, ask the real question: is it an "is a" (inheritance) or a "has a" (composition)? The next lesson gives you the right reflex.

Next step

Inheritance says "is a". But often, what you mean is "has a": a car has a engine, it is not an engine. That's composition, and it's the reflex the pros prefer.

Lesson 5: composition vs inheritance →
Accepter ou rejeter la conception de l'IA

Tu modélises une appli de gestion. L'IA te propose cette hiérarchie d'héritage pour un utilisateur premium. Ton rôle de relecteur : l'accepter telle quelle ou la rejeter, et dire pourquoi.

classe Utilisateur:
    nom, email
    seConnecter()

// L'IA traite "premium" comme un sous-type par héritage
classe UtilisateurPremium hérite de Utilisateur:
    dateFinAbonnement
    aDesAvantages()
À rejeter. Le test « est un » échoue : un utilisateur premium n'est pas une espèce d'utilisateur, c'est un utilisateur qui a un abonnement actif. Le jour où il résilie, il faudrait changer la classe de l'objet : impossible proprement avec l'héritage, qui est figé à la création. Le bon réflexe : un seul Utilisateur qui a un Abonnement (composition). On hérite pour un type permanent et stable (un CompteEpargne reste un compte), pas pour un statut qui va et vient.
Rappel libre

Sans remonter dans la leçon : en une phrase, qu'est-ce que l'héritage te permet d'éviter, et quelle question poses-tu avant d'y recourir ?

L'héritage évite de copier-coller le code commun : l'enfant extends le parent, récupère ses propriétés et méthodes (et appelle super() dans son constructeur), puis n'ajoute que ce qui change. Avant d'y recourir, demande-toi : est-ce vraiment un « est un » (héritage) ou plutôt un « a un » (composition) ? Si ce n'est pas un vrai « est un » stable, c'est probablement de la composition.
Que signifie « CompteEpargne hérite de Compte » ?
Quel est le principal danger de l'héritage ?
Besoin d'un développeur pour votre projet ?

Réponse sous 24h · Sans engagement