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.
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.
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.
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 extendsCompte. - The child reuses the parent for free, and writes only what changes.
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.
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.
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 →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()
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.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 ?
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.CompteEpargne hérite de Compte » ?