Templates de classes
Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy. Leçon 65 sur 104.
Tout comme les modèles de fonctions vous permettent d’écrire des fonctions indépendantes du type, les modèles de classes vous permettent de créer des classes indépendantes du type. C’est ainsi que fonctionnent les conteneurs comme std::vector : vous définissez la structure une seule fois, et le compilateur génère des versions spécifiques pour chaque type que vous utilisez.
template <typename T>
class Box {
T value;
public:
Box(T v) : value(v) {}
T getValue() const { return value; }
void setValue(T v) { value = v; }
};
int main() {
Box<int> intBox(42);
Box<std::string> strBox("Hello");
std::cout << intBox.getValue() << std::endl; // 42
std::cout << strBox.getValue() << std::endl; // Bonjour
}Tu indiques généralement le type entre chevrons lorsque tu crées des objets à partir de modèles de classe. Depuis C++17, le compilateur peut aussi le déduire des arguments du constructeur (Box b(42); crée un Box<int>), mais lorsqu’il n’y a aucun argument à partir duquel le déduire, tu dois écrire le type. Le compilateur génère alors une définition complète de la classe pour ce type précis.
Les modèles de classe peuvent avoir plusieurs paramètres de type et même des paramètres non typés, comme des entiers :
template <typename T, int Size>
class FixedArray {
T data[Size];
public:
T& operator[](int index) { return data[index]; }
int size() const { return Size; }
};
FixedArray<double, 5> arr; // Tableau de 5 doubles
arr[0] = 3.14;Lorsque vous définissez des fonctions membres en dehors de la classe, vous devez répéter la déclaration du modèle :
template <typename T>
class Container {
T* data;
public:
Container();
~Container();
};
template <typename T>
Container<T>::Container() : data(nullptr) {}
template <typename T>
Container<T>::~Container() { delete data; }Les modèles de classes constituent le fondement de la programmation générique en C++, et vous permettent d’écrire des structures de données réutilisables qui fonctionnent avec n’importe quel type.
Défi
FacileCréons un système de stockage générique à l’aide de modèles de classes afin de créer un conteneur flexible pouvant contenir n’importe quel type de données. Tu vas organiser ta classe modèle dans un fichier d’en-tête et démontrer sa polyvalence avec différents types dans ton programme principal.
Tu vas créer deux fichiers :
Storage.h: définis un modèle de classe appeléStoragequi sert de conteneur simple pour une seule valeur et propose quelques opérations utiles :Ton modèle
Storagedoit avoir :- Un membre privé pour stocker la valeur
- Un constructeur qui prend une valeur initiale
- Une méthode
getValue()qui renvoie la valeur stockée - Une méthode
setValue()qui met à jour la valeur stockée - Une méthode
isEmpty()qui renvoietruesi la valeur est égale à la valeur construite par défaut du type T, etfalsedans le cas contraire
Crée aussi un modèle de classe appelé
Pairavec deux paramètres de type, qui stocke deux valeurs liées :- Des membres privés pour la première et la deuxième valeur (qui peuvent être de types différents)
- Un constructeur qui initialise les deux valeurs
- Des méthodes
getFirst()etgetSecond()pour récupérer chaque valeur - Une méthode
display()qui affiche :(<first>, <second>)
main.cpp: lis quatre valeurs (chacune sur une ligne distincte) :- Une valeur entière
- Une nouvelle valeur entière
- Une valeur chaîne de caractères
- Une valeur décimale
Démontre le fonctionnement de tes modèles en :
- Créant un
Storage<int>avec le premier entier et en affichant :Int storage: <value> - Le mettant à jour avec le deuxième entier à l’aide de
setValue(), puis en affichant :Updated: <value> - Créant un
Storage<std::string>avec la chaîne de caractères saisie et en affichant :String storage: <value> - Vérifiant si le stockage de la chaîne est vide et en affichant :
Is empty: <true/false>(affichetrueoufalse) - Créant un
Pair<std::string, double>avec les valeurs de chaîne de caractères et décimale, puis en appelantdisplay() - Créant un
Pair<int, int>avec les deux valeurs entières saisies, puis en appelantdisplay()
Par exemple, avec les valeurs 42, 100, Hello et 3.14 :
Int storage: 42
Updated: 100
String storage: Hello
Is empty: false
(Hello, 3.14)
(42, 100)Remarque que le même modèle Storage fonctionne aussi bien avec des entiers qu’avec des chaînes de caractères, et que Pair peut associer différents types. Le compilateur génère des définitions de classe distinctes pour chaque combinaison de types que tu utilises. N’oublie pas d’utiliser la syntaxe template <typename T> pour les modèles à type unique et template <typename T, typename U> pour les modèles comportant plusieurs paramètres de type.
Essayez vous-même
#include <iostream>
#include <string>
#include "Storage.h"
using namespace std;
int main() {
// Lire les entrées
int intValue1;
int intValue2;
string strValue;
double doubleValue;
cin >> intValue1;
cin >> intValue2;
cin >> strValue;
cin >> doubleValue;
// TODO: Créer Storage<int> avec le premier entier et afficher : Int storage: <value>
// TODO: Mettre à jour avec le deuxième entier à l’aide de setValue(), afficher : Updated: <value>
// TODO: Créer Storage<std::string> avec la chaîne saisie et afficher : String storage: <value>
// TODO: Vérifier si le stockage de la chaîne est vide, afficher : Is empty: true/false
// TODO: Créer Pair<std::string, double> avec la chaîne et le nombre de type double, puis appeler display()
// TODO: Créer Pair<int, int> avec les deux entiers, puis appeler display()
return 0;
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Fondamentaux de la POO
Fichiers externesGénération et compilation en C++Fichiers d’en-tête et fichiers sourceEspaces de noms et portéeIntroduction à la POO en C++Classes et objetsLe pointeur « this »Méthodes (fonctions membres)Attributs (membres de données)Bases des constructeurs et destructeursRécapitulatif - Calculatrice simple4Propriétés de classe
Membres d’instance et statiquesAccesseurs et mutateursFonctions membres constMot-clé mutableMéthodes et variables statiquesFonctions et classes amiesRécapitulatif - Gestionnaire de compte bancaire7Héritage
Héritage de baseNiveaux d’accès de l’héritageOrdre d’appel des constructeurs et destructeursRedéfinition des méthodesFonctions virtuelles et VTableHéritage multipleHéritage virtuelRécapitulatif : hiérarchie des employés10Vue d’ensemble de la STL
Vue d’ensemble et philosophie de la STLConteneurs de la STLItérateursAlgorithmes de la STLFoncteurs et expressions lambdaRécapitulatif - fréquence des mots13Modèles de conception, partie 1
Introduction aux modèles de conceptionModèle SingletonFabrique et fabrique abstraiteModèle BuilderModèle ObserverModèle Strategy2Gestion de la mémoire
Mémoire de pile ou de tasPointeurs et référencesMémoire dynamique (new/delete)Pointeurs intelligents en C++RAII en C++Récapitulatif - Gestionnaire de tableaux dynamiques5Encapsulation
Spécificateurs d’accès en C++Spécificateurs d’accès en profondeurMasquage de l’informationStruct vs classeClasses imbriquées et internesRécapitulatif - Système de gestion des dossiers étudiants8Polymorphisme
Polymorphisme à la compilation vs à l’exécutionSurcharge de fonctionsRetour sur les fonctions virtuellesFonctions virtuelles puresClasses abstraitesConception d’interfaces en C++Conversion dynamique et RTTIRécapitulatif - Calculateur de formes3Constructeurs et destructeurs
Constructeur par défautConstructeur paramétréConstructeur de copieConstructeur de déplacementListes d’initialisation des constructeursConstructeurs déléguésApprofondissement des destructeursRègle des trois / cinq / zéroRécapitulatif - Classe String6Surcharge des opérateurs
Introduction à la surcharge des opérateursSurcharge des opérateurs arithmétiquesSurcharge des opérateurs de comparaisonOpérateurs de fluxSurcharge de l’opérateur d’affectationSurcharge des opérateurs [] et ()Opérateurs de conversion de typeRécapitulatif – Classe Matrix9Templates
Templates de fonctionsTemplates de classesSpécialisation des templatesTemplates variadiquesBases de SFINAE et des traits de typesRécapitulatif - Conteneur génériqueEntraînez-vous par vous-même : Compilateur C++ en ligne