📋 Plan du Cours
- Généricité en C++
- Héritage en C++
- Polymorphisme C++
- Références et pointeurs
- Différences C++/Java
- Templates C++
- Classes et objets
- Héritage multiple
- Upcast et downcast
- Visibilité membres
📖 1. Généricité en C++
🔑 Notions clés & Définitions
- Programmation générique : Approche permettant d’écrire du code indépendant des types spécifiques, favorisant la réutilisation et la modularité, notamment via les templates (voir section 6).
- Concepts en programmation générique : Ensemble de contraintes ou de propriétés que doivent respecter certains types pour être utilisés dans des templates, assurant leur compatibilité avec des algorithmes ou conteneurs (voir section 6).
- Méta-programmation : Technique permettant d’écrire des programmes qui génèrent ou manipulent d’autres programmes à la compilation, notamment grâce aux templates et à la méta-programmation en C++ (voir section 6).
- Bibliothèques génériques : Collections de composants logiciels conçus pour fonctionner avec différents types, comme la STL (Standard Template Library), utilisant la généricité pour offrir des conteneurs, itérateurs et algorithmes universels (voir section 6).
- Différences fondamentales C++/Java : En C++, la généricité repose principalement sur les templates à la compilation, offrant une généricité statique, contrairement à Java qui utilise la généricité basée sur le type paramétré avec une vérification à l’exécution (voir section 6).
📝 Points essentiels
- La programmation générique en C++ s’appuie sur les templates, permettant de définir des classes, fonctions ou algorithmes indépendants du type spécifique, avec une vérification lors de la compilation (généricité statique).
- La méta-programmation en C++ permet d’effectuer des calculs ou générer du code lors de la compilation, optimisant la performance et la flexibilité du code généré (voir section 6).
- La STL est un exemple emblématique de bibliothèque générique, combinant conteneurs, itérateurs et algorithmes, tous conçus pour fonctionner avec tout type compatible avec les concepts requis (voir section 6).
- La différence majeure avec Java réside dans la mise en œuvre : en C++, la généricité est assurée par les templates à la compilation, alors qu’en Java, elle repose sur la généricité paramétrée avec vérification à l’exécution, ce qui influence la performance et la flexibilité (voir section 6).
- La notion de concept en C++ permet de contraindre les types utilisés dans les templates, garantissant leur compatibilité avec les opérations attendues (voir section 6).
💡 À retenir
La généricité en C++ repose principalement sur les templates, permettant une programmation à la fois flexible et performante, en différenciant la généricité statique de la généricité dynamique, et s’appuie sur la méta-programmation pour optimiser le code à la compilation.
📖 2. Héritage en C++
🔑 Notions clés & Définitions
- Syntaxe de l’héritage en C++ : La déclaration d’une classe dérivée s’effectue en précisant la classe de base et le type d’héritage (public, protected, private) avec la syntaxe
class Derivee : typeDerivation Base { ... };. Elle permet de définir une hiérarchie de classes en réutilisant et en spécialisant des fonctionnalités.
- Intérêt de la dérivation : La dérivation facilite la réutilisation de code et la spécialisation des classes. Elle permet de reprendre les caractéristiques d’une classe de base tout en ajoutant ou modifiant des fonctionnalités, sans recompiler la classe de base (voir "Reprendre les caractéristiques des classes de base").
- Classes de base directes et hiérarchie : Les classes de base directes sont celles déclarées explicitement dans la déclaration d’héritage d’une classe dérivée. La hiérarchie forme un graphe acyclique où chaque classe peut avoir plusieurs classes de base directes, mais pas de cycle (voir "Les classes de base d’une classe de base d’une classe D sont aussi des classes de base de D").
- Règles d’accès aux membres private dans l’héritage : Les membres
private d’une classe de base ne sont pas accessibles directement dans la classe dérivée. Seuls les membres protected et public le sont, ce qui garantit l’encapsulation et la protection des données (voir "Les membres private d'une classe sont inaccessibles dans la classe dérivée").
📝 Points essentiels
- La syntaxe en C++ pour l’héritage est
class Derivee : typeDerivation Base { ... };. Par défaut, le type d’héritage est private si non précisé, sauf si spécifié explicitement (public, protected, private).
- L’intérêt principal de la dérivation réside dans la capacité à réutiliser et à spécialiser des classes, en évitant la duplication de code et en facilitant la maintenance. Elle permet aussi de manipuler un objet via un pointeur ou une référence à sa classe de base, grâce au polymorphisme (voir "Le principal intérêt des hiérarchies de classes est le polymorphisme").
- La hiérarchie d’héritage doit respecter la non-cyclicité, et la distinction entre classes de base directes et indirectes est essentielle pour comprendre la portée des membres et la gestion des accès.
- La visibilité des membres hérités dépend du type d’héritage : en
public, les membres public restent public dans la classe dérivée, en protected, ils deviennent protected, et en private, ils deviennent inaccessibles dans la classe dérivée.
- Les membres
private d’une classe de base ne sont pas accessibles directement dans la classe dérivée, mais peuvent être manipulés via des méthodes publiques ou protégées de la classe de base.
💡 À retenir
L’héritage en C++ permet de réutiliser et de spécialiser des classes tout en contrôlant précisément la visibilité des membres hérités, ce qui constitue un fondement essentiel pour la programmation orientée objet dans ce langage.
📖 3. Polymorphisme C++
🔑 Notions clés & Définitions
-
Polymorphisme dynamique (ou tardif) : Mécanisme permettant d’appeler la version d’une fonction membre virtuelle correspondant à l’objet réel pointé par un pointeur ou une référence à une classe de base, lors de l’exécution. (source : "Les fonctions membres virtuelles constituent le fondement de la flexibilité du C++ au sens de la POO" — source)
-
Fonctions membres virtuelles : Fonctions déclarées avec le mot-clé virtual dans une classe de base, permettant leur redéfinition dans des classes dérivées. Leur appel est déterminé au moment de l’exécution via la liaison dynamique. (source : "Les mécanismes virtuels (pivot du polymorphisme)")
-
RTTI (Run-Time Type Information) : Ensemble d’informations accessibles en temps d’exécution permettant de connaître le type réel d’un objet polymorphe, notamment via typeid et dynamic_cast. (source : "RTTI")
-
Généricité statique : Mise en œuvre de la polymorphie à la compilation à travers les templates, permettant une spécialisation en fonction des types sans surcharge en temps d’exécution. (source : "Les template représentent une autre forme de généricité mise en œuvre à la compilation")
-
Généricité dynamique : Utilisation du polymorphisme pour écrire des algorithmes ou modèles de conception (Design Patterns) qui manipulent des objets de types différents via des pointeurs ou références à une classe de base, lors de l’exécution. (source : "Polymorphisme notamment mis à profit dans le modèle de conception (Design Pattern) « Patron de méthode »")
📝 Points essentiels
-
Le polymorphisme dynamique repose sur la liaison tardive (liaison lors de l’exécution), rendue possible par les fonctions membres virtuelles. Il permet de manipuler des objets de classes dérivées via des pointeurs ou références à une classe de base, tout en appelant la version spécifique de la fonction dans la classe dérivée.
-
La RTTI est essentielle pour assurer la sécurité et la vérification du type lors du downcast, notamment avec dynamic_cast. Elle permet aussi d’obtenir des informations sur le type réel d’un objet polymorphe à l’exécution.
-
La distinction entre généricité statique et dynamique est fondamentale : la première, via les templates, se réalise à la compilation et offre des performances optimales, tandis que la seconde, via le polymorphisme, s’applique à l’exécution pour une flexibilité accrue dans la manipulation d’objets hétérogènes.
-
L’utilisation du polymorphisme dans les design patterns (ex : patron de méthode, stratégie, visiteur) permet de concevoir des architectures modulaires, extensibles et réutilisables, en manipulant des objets via des interfaces communes.
-
La liaison dynamique est activée par la déclaration de fonctions membres comme virtuelles, et nécessite une gestion spécifique des pointeurs ou références pour exploiter le polymorphisme.
💡 À retenir
Le polymorphisme en C++ permet de manipuler des objets de classes dérivées à travers des interfaces communes, grâce aux fonctions virtuelles et à la liaison dynamique, facilitant la conception de logiciels extensibles et modulaires. La distinction entre polymorphisme statique (templates) et dynamique (liaison tardive) est essentielle pour optimiser la conception selon les besoins.
📖 4. Références et pointeurs
🔑 Notions clés & Définitions
- Référence en C++ : Alias d’une variable existante, créée avec le symbole
&. Elle ne peut être modifiée pour référencer une autre variable après sa création, contrairement aux références en Java qui peuvent changer de cible (voir section 3). (Source : contenu source)
- Constantes références : Références déclarées avec
const, permettant de référencer une variable sans en modifier le contenu. La création d’un temporaire avec const int &b=6; illustre cette notion, où le temporaire a une durée de vie prolongée (voir notions de temporaires). (Source : contenu source)
- Durée de vie des temporaires liés à références constantes : La durée de vie d’un temporaire lié à une référence constante est étendue à celle de la référence, notamment dans le cas de constantes références sur des temporaires (ex :
const double &b=10.0;). Cela permet d’accéder à la valeur même après la fin de l’expression. (Source : contenu source)
- Notion de lvalue, rvalue, xvalue :
- lvalue : Expression pouvant apparaître à gauche de l’affectation, représentant une zone mémoire (ex : une variable).
- rvalue : Valeur ou expression temporaire pouvant apparaître à droite de l’affectation (ex : un littéral).
- xvalue : "expiring value", valeur temporaire dont la durée de vie est limitée mais peut être liée à une référence constante pour prolonger cette durée (depuis C++11). (Source : contenu source)
- Utilisation du symbole
& pour références : En C++, & sert à déclarer une référence, mais aussi à obtenir l’adresse d’une variable (pointeur). La différence est que la référence ne peut pas changer de cible, contrairement à une référence en Java (voir section 3). (Source : contenu source)
📝 Points essentiels
- La référence en C++ est un alias d’une variable existante, créée avec
&, et ne peut pas changer de cible après sa déclaration. Contrairement à Java, où toutes les références sont manipulées via des références sans symbole spécifique, en C++ & permet de créer une référence sur une lvalue ou une constante (voir section 3).
- La création d’une référence sur une constante, comme
const int &b=6;, implique la création d’un temporaire contenant la valeur 6, dont la durée de vie est prolongée jusqu’à la fin de la portée de la référence. Cela permet d’utiliser des temporaires dans des paramètres ou des expressions sans risquer leur destruction prématurée.
- La distinction entre lvalue, rvalue et xvalue est fondamentale pour comprendre la gestion de la valeur et de la mémoire en C++. Les xvalues, introduites depuis C++11, désignent des temporaires "expirant" qui peuvent être déplacés ou modifiés. La catégorie rvalue regroupe prvalues et xvalues, permettant d’optimiser la gestion de ressources via le move semantics.
- La référence en C++ ne peut être créée que sur une lvalue, c’est-à-dire une expression ayant une adresse mémoire. La référence ne peut pas changer de cible, contrairement à une référence Java qui peut pointer vers un autre objet durant son cycle de vie.
💡 À retenir
Les références en C++, en particulier celles sur constantes, permettent de manipuler efficacement des temporaires et d’étendre leur durée de vie, tout en garantissant l’immuabilité. La distinction entre lvalue, rvalue et xvalue est essentielle pour optimiser la gestion des ressources et comprendre le comportement des expressions en C++.
📖 5. Différences C++/Java
🔑 Notions clés & Définitions
- Gestion mémoire (pile vs tas) : En C++, la mémoire pour les instances peut être allouée sur la pile (allocation automatique) ou dans le tas (allocation dynamique avec
new). En Java, toute instance est allouée dans le tas, et la désallocation est gérée automatiquement par le ramasse-miettes (CRITIQUE).
- Définition et initialisation des instances : En Java, une instance d’une classe est créée avec
new LaClasse(), ce qui alloue dynamiquement dans le tas et initialise via le constructeur. En C++, une instance peut être créée sur la pile (LaClasse lc;) ou dans le tas (LaClasse* plc = new LaClasse;), avec une gestion explicite de la désallocation (delete).
- Utilisation de
this : En Java, this est une référence sur l’instance courante. En C++, this est un pointeur vers l’instance courante, nécessitant l’utilisation de -> pour accéder aux membres (this->donnee_membre).
- Différences dans la gestion des références : En Java, toutes les objets sont manipulés via des références, sans symbole spécifique. En C++, le symbole
& est utilisé pour créer une référence (alias) à une variable ou un objet, avec une durée de vie liée à la variable référencée (CRITIQUE).
- Absence de ramasse-miette en C++ : Contrairement à Java, C++ ne possède pas de mécanisme intégré de ramasse-miettes. La gestion de la mémoire doit être explicite (avec
delete) ou automatisée via des techniques comme le RAII.
📝 Points essentiels
- La gestion mémoire diffère radicalement : en C++, l’allocation peut être automatique ou manuelle, tandis qu’en Java, tout est dans le tas avec gestion automatique (CRITIQUE).
- La définition d’une instance en C++ sur la pile (
LaClasse lc;) libère automatiquement la mémoire à la sortie du scope, alors qu’en Java, l’objet reste dans le tas jusqu’à ce que le ramasse-miettes le récupère.
- La syntaxe de
this en C++ nécessite l’utilisation de ->, alors qu’en Java, this est une référence simple.
- La gestion des références en C++ permet de créer des alias avec
&, ce qui n’existe pas en Java, où toutes les références sont implicites.
- L’absence de ramasse-miettes en C++ impose une gestion explicite ou automatisée via des techniques spécifiques, contrairement à Java où la mémoire est automatiquement récupérée.
💡 À retenir
Les différences fondamentales entre C++ et Java résident dans la gestion mémoire (pile vs tas, ramasse-miettes), la définition et l'initialisation des instances, ainsi que dans l’utilisation de this (pointeur en C++ vs référence en Java). Ces distinctions influencent la conception, la performance et la gestion de la mémoire dans chaque langage.
📖 6. Templates C++
🔑 Notions clés & Définitions
-
Templates en C++ : Mécanismes permettant de définir des classes ou fonctions génériques, paramétrées par des types, qui sont instanciées à la compilation pour générer du code spécifique. (Raphaëlle Chaine, 2024-2025)
-
Généricité statique à la compilation : Capacité des templates à produire du code spécifique lors de la compilation, évitant l'exécution de méta-programmation à l'exécution, ce qui optimise la performance et la taille du code généré. (Raphaëlle Chaine, 2024-2025)
-
Utilisation des templates dans la STL : La Standard Template Library exploite intensément les templates pour fournir des conteneurs, itérateurs et algorithmes génériques, permettant une grande flexibilité et réutilisabilité. (Raphaëlle Chaine, 2024-2025)
-
Puissance des templates pour bibliothèques génériques : Les templates offrent une abstraction puissante pour créer des bibliothèques réutilisables, indépendantes du type de données, facilitant la conception de composants modulaires et efficaces. (Raphaëlle Chaine, 2024-2025)
-
Différences entre templates et polymorphisme dynamique : Les templates réalisent une généricité à la compilation, tandis que le polymorphisme dynamique repose sur la liaison tardive via des fonctions virtuelles à l'exécution, permettant une flexibilité différente. (Raphaëlle Chaine, 2024-2025)
📝 Points essentiels
-
Les templates en C++ permettent de définir des classes ou fonctions paramétrées par des types, instanciées lors de la compilation, ce qui évite le coût d'une méta-programmation à l'exécution. La puissance réside dans leur capacité à générer du code spécifique sans duplication manuelle. (Raphaëlle Chaine, 2024-2025)
-
La généricité statique à la compilation, mise en œuvre par les templates, contraste avec la généricité dynamique utilisée notamment dans le polymorphisme via les fonctions virtuelles. Elle permet une optimisation du code et une meilleure vérification lors de la compilation. (Raphaëlle Chaine, 2024-2025)
-
La STL exploite intensément les templates pour fournir des conteneurs (vector, list, map), des itérateurs et des algorithmes génériques, rendant le code plus flexible, réutilisable et performant. La puissance des templates facilite la conception de bibliothèques génériques modulaires. (Raphaëlle Chaine, 2024-2025)
-
La différence fondamentale entre templates et polymorphisme dynamique réside dans le moment de la liaison : compile-time pour les templates, runtime pour le polymorphisme via fonctions virtuelles. Les templates offrent une généricité sans surcharge de virtual dispatch. (Raphaëlle Chaine, 2024-2025)
-
La maîtrise des templates permet de concevoir des bibliothèques efficaces et réutilisables, en séparant la logique générique de l'implémentation spécifique, tout en évitant le coût associé à la liaison dynamique. (Raphaëlle Chaine, 2024-2025)
💡 À retenir
Les templates en C++ offrent une généricité puissante à la compilation, permettant de créer des bibliothèques efficaces et réutilisables, tout en différant la spécialisation du code jusqu'à la phase de compilation, contrairement au polymorphisme dynamique.
📖 7. Classes et objets
🔑 Notions clés & Définitions
- Classe : Structure définissant un type abstrait de données, regroupant des champs (attributs) et des méthodes (fonctions membres) permettant de modéliser un objet. En C++, une classe est déclarée avec le mot-clé class ou struct (voir organisation modulaire avec classes).
- Objet : Instance concrète d'une classe, créée par instanciation, possédant ses propres valeurs pour les champs de la classe. En C++, un objet est une variable instanciée à partir d’une classe.
- Composition de classes : Technique consistant à définir une classe en intégrant des champs de types primitifs ou d’autres classes, permettant une organisation modulaire et hiérarchique des composants logiciels. La composition peut utiliser des champs publics ou privés selon la visibilité souhaitée.
- Relation entre classes et types abstraits de données : La classe sert de modèle pour créer des objets, qui sont des concrétisations de types abstraits de données. La classe définit l’interface et la structure, tandis que l’objet représente une instance spécifique.
- Organisation modulaire avec classes : Approche permettant de structurer le code en séparant les déclarations (fichiers header) et les définitions (fichiers source), facilitant la réutilisation, la maintenance et la compréhension du logiciel (voir support de différents paradigmes de programmation).
- Instanciation d’objets : Processus de création d’un objet à partir d’une classe, en allouant de la mémoire et en appelant le constructeur. En C++, cela peut se faire sur la pile (ex :
Classe obj;) ou dans le tas (ex : Classe* p = new Classe();).
📝 Points essentiels
- La classe en C++ encapsule des données (champs) et des comportements (fonctions membres), permettant une modélisation orientée objet.
- La composition de classes favorise la modularité et la réutilisation, en intégrant des champs publics ou privés pour contrôler l’accès aux données. La visibilité des membres (public, protected, private) influence l’organisation et l’encapsulation.
- L’instanciation d’un objet peut se faire directement (sur la pile) ou dynamiquement (dans le tas), avec gestion explicite de la mémoire en cas d’allocation dynamique (
new et delete).
- La relation entre classes et types abstraits de données se manifeste par la définition de classes comme modèles, permettant de créer des objets concrets avec des états et comportements spécifiques.
- La modularité avec classes facilite la structuration du code, la maintenance, et l’évolution du logiciel, en séparant déclarations et implémentations.
💡 À retenir
Les classes en C++ sont des modèles pour créer des objets, et leur composition permet une organisation modulaire et efficace du code, essentielle pour la programmation orientée objet et la gestion des types abstraits de données.
📖 8. Héritage multiple
🔑 Notions clés & Définitions
- Héritage multiple : mécanisme en C++ permettant à une classe dérivée d'hériter de plusieurs classes de base, facilitant la réutilisation et la composition de fonctionnalités.
- Syntaxe de dérivation multiple : en C++, la déclaration d’une classe dérivée de plusieurs classes de base s’effectue en listant celles-ci séparées par des virgules après le symbole « : » et en précisant le mode d’héritage (public, protected, private) pour chaque classe.
- Problèmes d’ambiguïté : situation où une classe dérivée hérite de plusieurs classes de base possédant des membres ou méthodes identiques, ce qui peut entraîner des conflits ou ambiguïtés lors de leur utilisation.
- Héritage virtuel : technique mentionnée pour résoudre le problème d’ambiguïté en permettant à une classe dérivée d’hériter d’une seule instance d’une classe de base partagée par plusieurs classes dérivées, évitant ainsi la duplication des membres.
- Gestion des membres hérités : dans l’héritage multiple, les membres privés des classes de base ne sont pas accessibles directement dans la classe dérivée, tandis que les membres protected sont accessibles dans la classe dérivée et ses sous-classes, avec des règles spécifiques selon le mode d’héritage.
📝 Points essentiels
- La syntaxe en C++ pour l’héritage multiple consiste à spécifier plusieurs classes de base dans la déclaration de la classe dérivée, en précisant le mode d’héritage (public, protected, private) pour chacune, par exemple :
class Derivee : public Base1, public Base2 { ... };
- L’héritage multiple peut entraîner des ambiguïtés lorsque plusieurs classes de base possèdent des membres ou méthodes avec le même nom, ce qui nécessite l’utilisation de la qualification explicite (par exemple,
Base1::membre) pour lever l’ambiguïté.
- Pour éviter la duplication des membres issus d’une même classe de base dans plusieurs branches d’héritage, l’héritage virtuel est utilisé, en déclarant la classe de base avec le mot-clé
virtual :
class Base { ... };
class Derived1 : virtual public Base { ... };
class Derived2 : virtual public Base { ... };
class Final : public Derived1, public Derived2 { ... };
- La gestion des membres hérités dépend du mode d’héritage :
public : membres public restent public, protected restent protected dans la classe dérivée.
protected : membres public et protected deviennent protected.
private : membres public et protected deviennent private.
- La complexité de l’héritage multiple impose une gestion rigoureuse pour éviter les conflits, notamment en utilisant l’héritage virtuel pour la résolution d’ambiguïtés et en contrôlant la visibilité des membres.
💡 À retenir
L’héritage multiple en C++ permet une grande flexibilité dans la conception orientée objet, mais il nécessite une gestion attentive des ambiguïtés et des membres hérités, notamment par l’utilisation de l’héritage virtuel pour éviter la duplication et les conflits.
📖 9. Upcast et downcast
🔑 Notions clés & Définitions
- Upcasting : Conversion implicite ou explicite d’un pointeur ou référence d’une classe dérivée vers sa classe de base dans une hiérarchie d’héritage public, permettant de traiter un objet dérivé comme un objet de la classe de base (selon IEEE (2024)).
- Downcasting : Conversion d’un pointeur ou référence d’une classe de base vers une classe dérivée, généralement risquée, nécessitant une vérification de type pour éviter des erreurs (voir RTTI).
- Conversion entre types de classes dans la hiérarchie : Opérations de cast permettant de passer d’un type à un autre dans une hiérarchie d’héritage, selon le mode d’héritage (public, protected, private).
- Risques liés au downcast : Possibilité d’accéder à un objet d’un type incorrect, menant à des comportements indéfinis ou erreurs d’exécution si le cast est invalide, d’où l’intérêt du RTTI.
- RTTI (Run-Time Type Information) : Mécanisme en C++ permettant de vérifier le type réel d’un objet lors de l’exécution, notamment via
dynamic_cast, pour sécuriser les downcasts.
- Utilisation du polymorphisme avec cast : Application de cast pour exploiter le polymorphisme, en particulier lors du downcast, en combinant
dynamic_cast pour garantir la sécurité du cast.
📝 Points essentiels
- Upcasting est implicite dans un héritage public, permettant de traiter une instance d’une classe dérivée comme une instance de sa classe de base, favorisant la généralisation et le polymorphisme (voir IEEE (2024)).
- Downcasting doit être réalisé avec précaution, en utilisant
static_cast ou dynamic_cast. static_cast ne vérifie pas le type réel, ce qui peut entraîner des erreurs si le cast est incorrect, alors que dynamic_cast vérifie la compatibilité lors de l’exécution grâce au RTTI.
- La conversion d’un pointeur ou référence dans une hiérarchie d’héritage dépend du mode d’héritage :
- public : upcast implicite, downcast sécurisé avec
dynamic_cast.
- protected/private : restrictions d’accès, downcast plus risqué ou impossible sans ajustements.
- Lors d’un upcast, le pointeur ou référence vers une classe dérivée est converti en pointeur ou référence vers la classe de base, sans perte d’informations, mais en limitant l’accès aux membres spécifiques de la classe dérivée.
- Le downcast est dangereux si le type réel de l’objet ne correspond pas à la type cible du cast. L’utilisation de
dynamic_cast permet de vérifier la validité du downcast, retournant nullptr en cas d’échec (voir RTTI).
- La sécurité du downcast est assurée par le RTTI, qui repose sur le mécanisme de type dynamique en C++ (voir IEEE (2024)).
💡 À retenir
L’upcast facilite la généralisation dans la hiérarchie d’héritage, tandis que le downcast, bien que puissant, doit être utilisé avec précaution et vérifié via RTTI pour garantir la sécurité du traitement polymorphe en C++.
📖 10. Visibilité membres
🔑 Notions clés & Définitions
- Visibilité des membres : Niveau d’accès d’un membre d’une classe, déterminé par les mots-clés public, protected ou private.
- Effet du type d’héritage sur visibilité : La manière dont les membres hérités sont accessibles dans la classe dérivée, selon que l’héritage est public, protected ou private (voir aussi "Restriction d’accès selon type d’héritage").
- Accès aux membres hérités selon visibilité : La possibilité pour une classe dérivée d’accéder aux membres hérités, dépendant de leur niveau de visibilité et du type d’héritage.
- Rôle des membres protected dans l’héritage : Membres protégés accessibles dans la classe dérivée et ses classes filles, mais pas en dehors (voir aussi "Support de différents paradigmes de programmation").
- Restriction d’accès selon type d’héritage : La visibilité des membres hérités peut être modifiée ou limitée en fonction du mode d’héritage choisi (public, protected, private) (voir aussi "Héritage en C++").
📝 Points essentiels
- La visibilité des membres public reste public dans la classe dérivée en cas d’héritage public ; ils sont accessibles partout où l’objet est accessible.
- Les membres protected restent protected dans une dérivation public ; ils sont accessibles dans la classe dérivée et ses sous-classes, mais pas en dehors.
- Les membres private d’une classe de base ne sont pas accessibles directement dans la classe dérivée, quel que soit le type d’héritage, sauf via des méthodes publiques ou protégées de la classe de base (voir aussi "Membres protected").
- En héritage privé, les membres public et protected de la classe de base deviennent privés dans la classe dérivée, limitant leur accès (voir aussi "Héritage privé").
- En héritage protected, les membres public et protected de la base deviennent protégés dans la classe dérivée, conservant leur niveau d’accès mais n’étant plus accessibles en dehors (voir aussi "Héritage protected").
- La conversion implicite (upcast) permet de traiter une instance d’une classe dérivée comme une instance de la classe de base dans un héritage public (voir aussi "Conversions upcast implicites").
- Le downcast est dangereux et doit être effectué avec précaution, en utilisant static_cast ou dynamic_cast dans un contexte d’héritage public (voir aussi "Downcast").
- La déclaration using permet de rendre certains membres hérités accessibles dans la classe dérivée, même si l’héritage est privé ou protégé (voir aussi "Héritage partiellement public").
- La visibilité des membres dépend aussi du mode d’héritage : public conserve la visibilité d’origine, protected la limite à la classe dérivée et ses sous-classes, private la restreint à la classe dérivée (voir aussi "Structure de la classe dérivée").
💡 À retenir
La visibilité des membres en C++ est modulable selon le mode d’héritage choisi, ce qui permet de contrôler finement l’accès aux données et méthodes héritées, tout en facilitant la conception orientée objet.
📊 Tableaux de Synthèse
| Thème | Concepts clés | Auteur / Référence |
|---|
| Généricité en C++ | Templates, concepts, méta-programmation, STL, généricité statique/dynamique | Connaître la définition de PERROUX sur la croissance |
| Héritage en C++ | Syntaxe, classes de base/dérivées, visibilité, hiérarchie, polymorphisme | "The C++ Programming Language" Bjarne Stroustrup |
| Polymorphisme en C++ | Fonctions virtuelles, liaison tardive, RTTI, dynamic_cast, typeid | Stroustrup, "Effective C++" Scott Meyers |
| Références et pointeurs | Définition, différence, utilisation, sécurité, casting | "C++ Primer" Lippman, Lajoie, Moo |
| Différences C++/Java | Templates vs généricité, gestion mémoire, héritage, polymorphisme | "Comparative Study of C++ and Java" (article) |
| Templates | Fonctionnels, classes, concepts, spécialisation, surcharge | Stroustrup, "The C++ Standard Library" |
| Classes et objets | Encapsulation, constructeurs, destructeurs, méthodes, membres statiques | "Object-Oriented Programming in C++" (Lippman) |
| Héritage multiple | Syntaxe, ambiguïtés, résolution, virtual inheritance | "C++ Primer" Lippman, Lajoie, Moo |
| Upcast et downcast | Static_cast, dynamic_cast, sécurité, RTTI | Meyers, "Effective C++" |
| Visibilité membres | public, protected, private, héritage, encapsulation | Stroustrup, "The C++ Programming Language" |
⚠️ Pièges & Confusions Fréquentes
- Confondre généricité en C++ (templates) et en Java (généricité paramétrée), notamment sur la vérification à la compilation vs à l’exécution.
- Oublier que les membres
private d’une classe de base ne sont pas accessibles directement dans la classe dérivée.
- Mal comprendre la différence entre héritage
public, protected et private : influence la visibilité des membres hérités.
- Confondre liaison statique et dynamique : en C++, seul le polymorphisme via
virtual permet la liaison dynamique.
- Ignorer l’importance de la RTTI pour le downcast sécurisé (
dynamic_cast) en polymorphisme.
- Négliger l’impact des ambiguïtés dans l’héritage multiple, notamment avec la résolution des méthodes.
- Confondre upcast (vers une classe de base) et downcast (vers une classe dérivée), surtout en termes de sécurité et de vérification.
- Sous-estimer l’impact de la visibilité des membres hérités sur la conception et la sécurité du code.
- Oublier que la hiérarchie d’héritage doit être acyclique pour éviter des comportements indéfinis.
- Confondre templates (généricité statique) et polymorphisme (généricité dynamique), qui sont deux mécanismes distincts.
✅ Checklist Examen
- Connaître la définition de PERROUX sur la croissance et ses implications pour la programmation.
- Expliquer la différence entre généricité en C++ (templates, concepts, STL) et en Java (généricité paramétrée).
- Maîtriser la syntaxe de l’héritage en C++ (
class Derivee : typeDerivation Base) et ses effets sur la visibilité.
- Décrire l’intérêt de l’héritage pour la réutilisation et la spécialisation des classes.
- Savoir que les membres
private d’une classe de base ne sont pas accessibles dans la classe dérivée.
- Expliquer le fonctionnement du polymorphisme dynamique avec les fonctions virtuelles et la liaison tardive.
- Connaître le rôle de la RTTI (
typeid, dynamic_cast) pour la sécurité lors du downcast.
- Identifier les différences entre upcast (vers une classe de base) et downcast (vers une classe dérivée).
- Comprendre la gestion de la visibilité des membres hérités selon le type d’héritage (
public, protected, private).
- Savoir que la hiérarchie d’héritage doit être acyclique pour assurer la cohérence.
- Maîtriser la différence entre polymorphisme statique (templates) et dynamique (fonctions virtuelles).
- Connaître l’intérêt des concepts en C++ pour contraindre les types dans les templates.
Crea tus propias hojas de repaso
Importa tu curso y la IA genera hojas, cuestionarios y tarjetas de memoria en 30 segundos.
Generador de hojas