Comment utiliser les modèles C ++

Comment utiliser les modèles C ++
Dans la programmation C ++ de base, le type de données, E.g., int ou char, doit être indiqué dans une déclaration ou une définition. Une valeur telle que 4 ou 22 ou -5 est un int. Une valeur telle que «A» ou «B» ou «C» est un char. Le mécanisme de modèle permet au programmeur d'utiliser un type générique pour un ensemble de types réels. Par exemple, le programmeur peut décider d'utiliser l'identifiant T pour INT ou CHAR. Il est possible qu'un algorithme C ++ ait plus d'un type générique. Avec, disons, pour l'int ou le char, u peut représenter le type de flotteur ou de pointeur. Une classe, comme la classe de chaîne ou de vecteur, est comme un type de données, et les objets instanciés sont comme des valeurs du type de données, qui est la classe spécifiée. Ainsi, le mécanisme de modèle permet également au programmeur d'utiliser un identifiant de type générique pour un ensemble de classes.

Un modèle C ++ crée un algorithme indépendant du type de données utilisées. Ainsi, le même algorithme, avec de nombreuses occurrences du même type, peut utiliser différents types à différentes exécutions. Les entités de variable, de fonction, de structure et de classe peuvent avoir des modèles. Cet article explique comment déclarer des modèles, comment définir des modèles et comment les appliquer en C++. Vous devriez déjà avoir une connaissance des entités susmentionnées pour comprendre les sujets abordés dans cet article.

Les types

Scalaire

Les types scalaires sont vides, bool, char, int, float et pointeur.

Classes comme types

Une classe particulière peut être considérée comme un type et ses objets que les valeurs possibles.

Un type générique représente un ensemble de types scalaires. La liste des types scalaires est vaste. Le type INT, par exemple, a d'autres types connexes, tels que l'int court, le long int, etc. Un type générique peut également représenter un ensemble de classes.

Variable

Un exemple de déclaration et de définition de modèle est la suivante:

modèle T pi = 3.14

Avant de continuer, notez que ce type d'instruction ne peut pas apparaître dans la fonction principale () ou toute portée de bloc. La première ligne est la déclaration de tête de modèle, avec le nom de type générique choisi par le programmeur, t. La ligne suivante est la définition de l'identifiant, Pi, qui est du type générique, t. La précision, de savoir si le T est un INT ou un flotteur ou un autre type, peut être effectué dans la fonction C ++ Main () (ou une autre fonction). Une telle précision sera effectuée avec le Pi variable, et non t.

La première ligne est la déclaration de tête de modèle. Cette déclaration commence par le mot réservé, le modèle, puis les supports à angle ouvert et fermé. Dans les supports d'angle, il y a au moins un identifiant de type générique, comme t, ci-dessus. Il peut y avoir plus d'un identifiant de type générique, chacun précédé du mot réservé, typename. Ces types génériques dans cette position sont appelés paramètres de modèle.

L'énoncé suivant peut être écrit dans main () ou dans toute autre fonction:

couter << pi << '\n';

Et la fonction afficherait 3.14. L'expression pi décide le type exact de t pour le Pi variable. La spécialisation décide du type de données particulier du paramètre de modèle. L'instanciation est le processus interne C ++ de création du type particulier, comme Float, dans ce cas. Ne confondez pas entre instanciation d'un paramètre de modèle et instanciation d'une classe. Dans le sujet du modèle, de nombreux types de données peuvent avoir un nom de type générique, tandis que de nombreuses classes peuvent avoir un nom de classe générique. Cependant, le nom de classe générique des classes est simplement appelé une classe, et non comme un nom de classe. De plus, une valeur est pour un type de données, comme l'INT, car un objet instancié concerne une classe, comme la classe de chaîne.

À la spécialisation, le type de données choisi, tel que Float, est placé dans des supports d'angle après la variable. S'il y a plus d'un paramètre de modèle dans la déclaration de tête de modèle, il y aura un nombre correspondant de types de données dans le même ordre dans l'expression de spécialisation.

À la spécialisation, un type est connu comme un argument de modèle. Ne confondez pas entre cela et l'argument de la fonction pour l'appel de la fonction.

Type par défaut

Si aucun type n'est donné à la spécialisation, le type par défaut est supposé. Donc, à partir de l'expression suivante:

modèle U pi = "amour";

Cette came soit utilisée en tant que telle avec un type par défaut:

couter << pi << '\n';

Par lequel «l'amour» pour le pointeur constant vers Char est utilisé par défaut du modèle. Remarque dans la déclaration que u = const char *. Les supports d'angle seront vides à la spécialisation (aucun type donné); Le type réel est considéré comme un pointeur const vers char, le type par défaut. Si un autre type était nécessaire à la spécialisation, alors le nom de type serait écrit dans les supports d'angle. Lorsque le type par défaut est souhaité à la spécialisation, la répétition du type dans les supports d'angle est facultative, je.e., Les supports d'angle peuvent être laissés vides.

Remarque: le type par défaut peut toujours être modifié à la spécialisation en ayant un type différent.

structure

L'exemple suivant montre comment un paramètre de modèle peut être utilisé avec une structure:

modèle structure

T John = 11;
T Peter = 12;
T Mary = 13;
T Joy = 14;
;

Ce sont des âges des élèves en classe (classe). La première ligne est la déclaration de modèle. Le corps en accolades est la définition réelle du modèle. Les âges peuvent être sortis dans la fonction principale () avec ce qui suit:

Âge grade7;
couter << grade7.John << " << grade7.Mary << '\n';

La sortie est: 11 13. La première déclaration ici effectue la spécialisation. Notez comment il a été fabriqué. Il donne également un nom pour un objet de la structure: grade7. La deuxième déclaration a des expressions d'objets struct ordinaires. Une structure est comme une classe. Ici, Ages est comme un nom de classe, tandis que Grade7 est un objet de la classe (struct).

Si certains âges sont des entiers et que d'autres sont des flotteurs, alors la structure a besoin de deux paramètres génériques, comme suit:

modèle structure

T John = 11;
U peter = 12.3;
T Mary = 13;
U joie = 14.6;
;

Un code pertinent pour la fonction principale () est le suivant:

Âge grade7;
couter << grade7.John << " << grade7.Peter << '\n';

La sortie est: 11 12.3. À la spécialisation, l'ordre des types (arguments) doit correspondre à l'ordre des types génériques dans la déclaration.

La déclaration du modèle peut être séparée de la définition, comme suit:

modèle structure

T John;
U Peter;
T Mary;
U joie;
;
Âge grade7 = 11, 12.3, 13, 14.6;

Le premier segment de code est purement une déclaration d'un modèle (il n'y a pas de cession). Le deuxième segment de code, qui n'est qu'une déclaration, est la définition de l'identifiant, grade7. Le côté gauche est la déclaration de l'identifiant, grade7. Le côté droit est la liste d'initialisateur, qui attribue des valeurs correspondantes aux membres de structure. Le deuxième segment (instruction) peut être écrit dans la fonction principale (), tandis que le premier segment reste en dehors de la fonction principale ().

Non-type

Des exemples de types non de données incluent l'INT, le pointeur vers l'objet, le pointeur pour fonctionner et les types automobiles. Il existe d'autres non-types, que cet article ne traite pas. Un non-type est comme un type incomplet, dont la valeur est donnée plus tard et ne peut pas être modifiée. En tant que paramètre, il commence par un non-type particulier, suivi d'un identifiant. La valeur de l'identifiant est donnée plus tard, à la spécialisation, et ne peut pas être modifiée à nouveau (comme une constante, dont la valeur est donnée plus tard). Le programme suivant illustre ceci:

#inclure
Utilisation de Namespace Std;
modèle structure

T John = n;
U peter = 12.3;
T Mary = n;
U joie = 14.6;
;
int main()

Âge grade7;
couter << grade7.John << " << grade7.Joy << '\n';
retour 0;

À la spécialisation, le premier type, int, dans les supports d'angle est là plus pour la formalité, pour s'assurer que le nombre et l'ordre des paramètres correspondent au nombre et à l'ordre des types (arguments). La valeur de n a été donnée à la spécialisation. La sortie est: 11 14.6.

Spécialisation partielle

Supposons qu'un modèle a quatre types génériques et que, parmi les quatre types, il y a un besoin de deux types par défaut. Cela peut être réalisé en utilisant la construction de spécialisation partielle, qui n'utilise pas l'opérateur d'affectation. Ainsi, la construction de spécialisation partielle donne des valeurs par défaut à un sous-ensemble de types génériques. Cependant, dans le schéma de spécialisation partiel, une classe de base (struct) et une classe de spécialisation partielle (struct) sont nécessaires. Le programme suivant l'illustre pour un type générique sur deux types génériques:

#inclure
Utilisation de Namespace Std;
// classe de modèle de base
modèle
structure

;
// Spécialisation partielle
modèle
structure

T1 John = 11;
Float Peter = 12.3;
T1 Mary = 13;
float joie = 14.6;
;
int main()

Âge grade7;
couter << grade7.John << " << grade7.Joy << '\n';
retour 0;

Identifiez la déclaration de classe de base et sa définition de classe partielle. La déclaration de la tête de modèle de la classe de base a tous les paramètres génériques nécessaires. La déclaration de tête de modèle de la classe de spécialisation partielle a le type générique uniquement. Il y a un ensemble supplémentaire de supports d'angle utilisés dans le schéma qui vient juste après le nom de la classe dans la définition de spécialisation partielle. C'est ce qui fait réellement la spécialisation partielle. Il a le type par défaut et le type non défaut, dans l'ordre écrit dans la classe de base. Notez que le type par défaut peut toujours recevoir un type différent dans la fonction principale ().

Le code pertinent dans la fonction principale () peut être le suivant:

Âge grade7;
couter << grade7.John << " << grade7.Joy << '\n';

La sortie est: 11 14.6.

Pack de paramètres de modèle

Un pack de paramètres est un paramètre de modèle qui accepte zéro ou plus de modèles de type génériques pour les types de données correspondants. Le paramètre du pack de paramètres commence par le mot réservé typename ou classe. Ceci est suivi par trois points, puis l'identifiant du pack. Le programme suivant illustre comment un pack de paramètres de modèle peut être utilisé avec une structure:

#inclure
Utilisation de Namespace Std;
modèle structure

int John = 11;
Float Peter = 12.3;
int Mary = 13;
float joie = 14.6;
;
int main()

Âge catégorie B;
couter << gradeB.John << " << gradeB.Mary << '\n';
Âge gradec;
couter << gradeC.Peter << " << gradeC.Joy << '\n';
Âge classé;
couter << gradeD.John << " << gradeD.Joy << '\n';
Âges Gradea; // Comme par défaut
couter << gradeA.John << " << gradeA.Joy << '\n';
retour 0;

La sortie est:

11 13
12.3 14.6
11 14.6
11 14.6

Modèles de fonction

Les fonctionnalités de modèle mentionnées ci-dessus s'appliquent de manière similaire à des modèles de fonction. Le programme suivant montre une fonction avec deux paramètres de modèle générique et trois arguments:

#inclure
Utilisation de Namespace Std;
modèle void func (t non, u cha, const char * str)
couter << "There are " << no << " books worth " << cha << str << " in the store." << '\n';

int main()
func (12, '$', "500");
retour 0;

La sortie est la suivante:

Il y a 12 livres d'une valeur de 500 $ dans le magasin.

Séparation du prototype

La définition de la fonction peut être séparée de son prototype, comme le montre le programme suivant:

#inclure
Utilisation de Namespace Std;
modèle void func (t non, u cha, const char * str);
modèle void func (t non, u cha, const char * str)
couter << "There are " << no << " books worth " << cha << str << " in the store." << '\n';

int main()
func (12, '$', "500");
retour 0;

Note: La déclaration du modèle de fonction ne peut pas apparaître dans la fonction principale () ou dans toute autre fonction.

Surcharge

La surcharge de la même fonction peut avoir lieu avec différentes déclarations de tête de modèle. Le programme suivant illustre ceci:

#inclure
Utilisation de Namespace Std;
modèle void func (t non, u cha, const char * str)
couter << "There are " << no << " books worth " << cha << str << " in the store." << '\n';

modèle void func (t non, const char * str)
couter << "There are " << no << " books worth $" << str << " in the store." << '\n';

int main()

func (12, '$', "500");
func (12, "500");
retour 0;

La sortie est:

Il y a 12 livres d'une valeur de 500 $ dans le magasin.

Il y a 12 livres d'une valeur de 500 $ dans le magasin.

Modèles de classe

Les caractéristiques des modèles mentionnés ci-dessus s'appliquent de manière similaire aux modèles de classe. Le programme suivant est la déclaration, la définition et l'utilisation d'une classe simple:

#inclure
Utilisation de Namespace Std;
classe TheCla

public:
int num;
Char statique Ch;
void func (char cha, const char * str)
couter << "There are " << num << " books worth " << cha << str << " in the store." << '\n';

STATIC VOID FUN (char ch)
if (ch == 'a')
couter << "Official static member function" << '\n';

;
int main()

Thecla obj;
obj.num = 12;
obj.func ('$', "500");
retour 0;

La sortie est la suivante:

Il y a 12 livres d'une valeur de 500 $ dans le magasin.

Le programme suivant est le programme ci-dessus avec une déclaration de tête de modèle:

#inclure
Utilisation de Namespace Std;
modèle classe TheCla

public:
T num;
statique u ch;
void func (u cha, const char * str)
couter << "There are " << num << " books worth " << cha << str << " in the store." << '\n';

STATIC VOID FUN (U CH)
if (ch == 'a')
couter << "Official static member function" << '\n';

;
int main()

Thecla obj;
obj.num = 12;
obj.func ('$', "500");
retour 0;

Au lieu du mot typename dans la liste des paramètres du modèle, la classe de mots peut être utilisée. Notez la spécialisation dans la déclaration de l'objet. La sortie est toujours la même:

Il y a 12 livres d'une valeur de 500 $ dans le magasin.

Déclaration de séparation

La déclaration de modèle de classe peut être séparée du code de classe, comme suit:

modèle classe thecla;
modèle classe thecla
public:
T num;
statique u ch;
void func (u cha, const char * str)
couter << "There are " << num << " books worth " << cha << str << " in the store." << '\n';

STATIC VOID FUN (U CH)
if (ch == 'a')
couter << "Official static member function" << '\n';

;

Traiter avec des membres statiques

Le programme suivant montre comment accéder à un membre de données statique et à une fonction de membre statique:

#inclure
Utilisation de Namespace Std;
modèle classe thecla
public:
T num;
statique u ch;
void func (u cha, const char * str)
couter << "There are " << num << " books worth " << cha << str << " in the store." << '\n';

STATIC VOID FUN (U CHA)
if (ch == 'a')
couter << "Official static member function" << cha << '\n';

;
modèle U thecla:: ch = 'a';
int main()

Thecla::amusant('.');
retour 0;

L'attribution d'une valeur à un membre de données statique est une déclaration et ne peut pas être dans Main (). Remarquez l'utilisation et les positions des types génériques et le type générique de données dans l'instruction Affectation. De plus, notez que la fonction de membre de données statique a été appelée dans Main (), avec les types de données de modèle réels. La sortie est la suivante:

Fonction officielle des membres statiques.

Compilation

La déclaration (en-tête) et la définition d'un modèle doivent être dans un seul fichier. C'est-à-dire qu'ils doivent être dans la même unité de traduction.

Conclusion

Les modèles C ++ font un algorithme indépendant du type de données utilisées. Les entités de variable, de fonction, de structure et de classe peuvent avoir des modèles, qui impliquent la déclaration et la définition. La création d'un modèle implique également une spécialisation, c'est-à-dire lorsqu'un type générique prend un type réel. La déclaration et la définition d'un modèle doivent être à la fois dans une seule unité de traduction.