Problème de classe template
Résolu/Fermé
Mourad2009B
Messages postés
118
Date d'inscription
lundi 23 août 2010
Statut
Membre
Dernière intervention
5 février 2025
-
Modifié le 16 mars 2022 à 12:07
Mourad2009B Messages postés 118 Date d'inscription lundi 23 août 2010 Statut Membre Dernière intervention 5 février 2025 - 16 mars 2022 à 17:06
Mourad2009B Messages postés 118 Date d'inscription lundi 23 août 2010 Statut Membre Dernière intervention 5 février 2025 - 16 mars 2022 à 17:06
A voir également:
- Problème de classe template
- Logiciel de classement de photos gratuit - Guide
- Bluetooth mercedes classe a 2005 - Forum Autoradio
- Classe ram - Guide
- Logiciel de classement de documents gratuit - Télécharger - Bureautique
- Explorer.exe classe non enregistrée - Forum Windows 10
3 réponses
Dalfab
Messages postés
706
Date d'inscription
dimanche 7 février 2016
Statut
Membre
Dernière intervention
2 novembre 2023
101
15 mars 2022 à 21:15
15 mars 2022 à 21:15
Bonjour,
Une fonction ni
Une fonction
Si la fonction est
On peut tout de même définir une template fonction dans un fichier source, mais il faut alors explicitement indiquer les spécialisations que l'on veut instancier, indiquer qu'on les exporte vers les autres unités de compilation, et aussi indiquer explicitement leur importation. C'est un cas rare et complexe, donc la plupart du temps on doit les définir dans l'entête.
Une fonction ni
inlineni
templatedoit normalement être définie dans un fichiers source. Si dans un header utilisé dans plusieurs unités de compilation on a une erreur de redéfinition.
Une fonction
inlinepeut être définie dans un fichier d'entête pour pouvoir l'utiliser dans plusieurs unités de compilation, on n'aura pas de problème de redéfinition.
Si la fonction est
template, la définition doit être visible de l'endroit où va utiliser une spécialisation du
template. Donc une template fonction doit normalement être définie dans un entête. A noter que pour les template fonctions on n'a pas besoin d'ajouter le mot
inline, il est sous-entendu.
On peut tout de même définir une template fonction dans un fichier source, mais il faut alors explicitement indiquer les spécialisations que l'on veut instancier, indiquer qu'on les exporte vers les autres unités de compilation, et aussi indiquer explicitement leur importation. C'est un cas rare et complexe, donc la plupart du temps on doit les définir dans l'entête.
mamiemando
Messages postés
33535
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
12 février 2025
7 828
16 mars 2022 à 12:58
16 mars 2022 à 12:58
Bonjour,
Quelques précisions qui complète la réponse de Dalfab :
Quelques rappels préalables sur les headers et le linkage
Tout ce qui est dans cette section s'applique au C et au C++.
Lorsque le compilateur traite un fichier source (
Supposons que cette fonction
Cependant, ça n'est pas suffisant.
Ce que je viens d'expliquer s'étend à tout ce qui est global et nommé : fonctions, structures, unions, etc. En C++, s'ajoutent à cette liste les classes et méthodes. Ces noms sont généralement appelés "symboles" par le compilateur.
Que fait le mot clé
Le mot clé
Il faut commencer par comprendre ce qu'est un
parce que dans ton code tu veux utiliser des
Le mot clé
Le mot clé
Pour une fonction normale, le compilateur prévoit un appel et tout ce que cela comporte (recopie des paramètres dans la pile, exécution de la fonction, retour à la fonction appelante).
En C++, quand une fonction est
Il a un autre effet. Comme la fonction
En d'autres termes, si tu veux implémenter une fonction (non template) dans un header, celle-ci doit être
Résumé
Bonne chance
Quelques précisions qui complète la réponse de Dalfab :
Quelques rappels préalables sur les headers et le linkage
Tout ce qui est dans cette section s'applique au C et au C++.
Lorsque le compilateur traite un fichier source (
.cpp), chacune des fonctions (non statiques) de ce fichier est "référencée" dans le
.oengendré à la compilation. C'est ce référencement qui va permettre au linker de retrouver le code binaire des fonctions au moment de construire le binaire final (l'exécutable ou la librairie que tu es en train de concevoir). Si un même nom (appelé symbole) est utilisé à plusieurs endroits (typiquement, la fonction
fest référencée dans deux
.odifférent), le linker (c'est-à-dire la partie du compilateur qui "recolle" les modules entre eux pour former le binaire final) ne peut pas savoir de quelle fonction
f
tu parles et plantera en te disant qu'il y a une définition multiple.
Supposons que cette fonction
f
soit commune à deux modules (disons a.cppet
b.cpp), on ne peut pas se permettre de la copier coller dans ces deux fichiers, sans quoi on aura une erreur de linkage. Si on implémente la fonction
f
dans f.cppet qu'on inclue ce fichier dans
a.cppet
b.cpp, alors on a toujours le même problème, puisque faire un
#includerevient à copier coller le contenu du fichier. On ne peut donc se permettre que d'inclure sa déclaration. Et c'est typiquement ce qu'on va mettre dans un fichier header (disons
f.hpp) que l'on incluera depuis
a.cppet
b.cpp,, tandis que le code de
frestera dans
f.cpp.
Cependant, ça n'est pas suffisant.
a.oet
b.osont compilés indépendamment et si on n'a pas veillé à mettre un verrou au niveau du
f.hpp(e.g.
#ifndef F_HPP #define F_HPP ... #endif) on aura f qui sera déclaré dans
a.oet
b.o. Une fois cette précaution prise, tout se passe bien. Peut importe dans quel ordre le compilateur traite
a.oet
b.o, au moment de traiter le premier des deux, il découvrira la déclaration de
fet au moment de traiter le second il ne réincluera pas
f.hpptout en ayant en tête sa déclaration. Au moment du linkage, le compilateur contrôle que la fonction
f
que tu as déclaré est implémentée une et une seule fois (donc dans un seul fichier .o, ici
f.o).
Ce que je viens d'expliquer s'étend à tout ce qui est global et nommé : fonctions, structures, unions, etc. En C++, s'ajoutent à cette liste les classes et méthodes. Ces noms sont généralement appelés "symboles" par le compilateur.
Que fait le mot clé
template
Le mot clé
templateétant spécifique au C++, ce qui est expliqué ici ne concerne pas le C.
Il faut commencer par comprendre ce qu'est un
templateet ce que fait un compilateur. Un compilateur détermine pour chaque variable son type et en déduit la taille qu'elle occupe en mémoire.
- Supposons que tu veuilles utiliser la classe template
std::vector<T>
parce que dans ton code tu veux utiliser des
std::vector<int>, des
std::vector<double>. Un
intest plus petit qu'un
doubleet on comprend qu'en mémoire, ces deux structures ne feront pas la même taille (et n'ont pas le même type). En C, il faudrait coder une classe
vector_intet
vector_doublequi seraient identique aux types prêts. En C++, on peut éviter ça grâce au mot clé
template. Mais ce dernier ne dispense pas le compilateur de devoir générer "en interne" une classe qui correspond à ce que j'ai appelé
vector_int
et vector_double
.
- Maintenant, la classe template
std::vector<T>
est définie dans la STL. Or la STL ne peut pas "deviner" les vecteurs que tu vas avoir envie de construire dans ton programme. Il n'est donc pas possible de les compiler par avance. - Il faut donc que ton programme sache quel est le code de
std::vector<T>
et donc pour ça il doit l'inclure. Or, comme tu le sais, en C et en C++, on ne doit inclure QUE des headers. Ainsi, pour être réutilisable dans d'autres fichiers, le code template doit nécessairement être écrit dans un header- La seule exception à cette règle, c'est si ta classe template n'est utilisée que dans un fichier source. Dans ce cas, tu pourrais te permettre de déclarer cette classe template dans ce fichier source, puisque la classe template n'est résolue nulle part ailleurs).
- Au moment de compiler ton programme, le compilateur découvre toutes tes utilisations
std::vector<T>
et compiler ses déclinaisons, puis les utiliseras pour compiler ton programme.
Le mot clé
inline
Le mot clé
inlineétant spécifique au C++, ce qui est expliqué ici ne concerne pas le C.
Pour une fonction normale, le compilateur prévoit un appel et tout ce que cela comporte (recopie des paramètres dans la pile, exécution de la fonction, retour à la fonction appelante).
En C++, quand une fonction est
inline, le compilateur substitue son appel par le code de la fonction elle même. Cela veut dire que si ta fonction inline est appelée a 100 endroits dans ton code, le binaire associé à ta fonction
inlineest copié à ces 100 endroits. Bien entendu, ce "copier coller" induit un binaire plus gros, mais il permet d'optimiser l'exécution car on évite de recopier des paramètres en pile. Cependant, ce coût fait qu'on réserve ce mot clé généralement aux fonctions/méthodes courtes.
Il a un autre effet. Comme la fonction
inlineest substituée, son nom n'est pas un symbole en tant que tel (voir la section qui fait les rappels préalables sur le linkage). Cela veut dire que contrairement à une fonction ordinaire, une fonction
inlinepeut être implémentée dans un header sans engendrer de définitions multiples.
En d'autres termes, si tu veux implémenter une fonction (non template) dans un header, celle-ci doit être
inline, sinon tu cours le risque d'avoir une définition multiple.
Résumé
- Une classe template est généralement codée dans un fichier header. On ne peut se permettre de l'implémenter dans un fichier source que si elle n'est utilisée que dans ce fichier source.
- Les fonctions / méthodes / classes / structures / ... sont généralement déclarées dans un header, ce qui permet de les réutiliser dans d'autres fichiers. Les méthodes et fonctions sont implémentées dans le fichier source. Le header est verrouillé pour n'être inclu qu'une fois au moment de la compilation. Ces conventions permettent de garantir que chaque symbole est déclaré une et une seule fois et compilé une et une seule fois, ce qui évite les erreurs de linkage (définition ou déclarations multiples, symbole indéfinis, etc).
- Le mot clé inline permet d'implémenter une fonction dans un header, car une telle fonction n'engendre pas de symbole au moment de compiler. Il est généralement réservé au fonction courte. Il n'a rien à voir avec la notion de
template
. Une classe template peut comporter (ou pas) des méthodesinline
, c'est une considération indépendantes.
Bonne chance
Mourad2009B
Messages postés
118
Date d'inscription
lundi 23 août 2010
Statut
Membre
Dernière intervention
5 février 2025
Modifié le 16 mars 2022 à 19:16
Modifié le 16 mars 2022 à 19:16
Bonjour Daflab,
Merci pour tes éclaircissements, ça permet de gagner du temps, (beaucoup de temps)
C'est un exemple que j'ai trouvé dans un livre, mais maintenant je déclare tout dans le fichier header
Merci beaucoup.
Merci pour tes éclaircissements, ça permet de gagner du temps, (beaucoup de temps)
C'est un exemple que j'ai trouvé dans un livre, mais maintenant je déclare tout dans le fichier header
#ifndef POINT_H #define POINT_H #include <iostream> #include <windows.h> template <class T> class point { public: point(T abs=0, T ord=0) { x = abs, y = ord; } void Affiche() const; private: T x, y; }; template<class T> void point<T>::Affiche() const { unsigned int temp = GetConsoleOutputCP(); SetConsoleOutputCP(CP_UTF8); std::cout << "coordonnées : x = " << x << ", y = " << y << std::endl; SetConsoleOutputCP(temp); } //Spécialisation pour les char template<> void point<char>::Affiche() const { std::cout << "coordonnées : x = " << (int)x << ", y = " << (int)y << std::endl; } #endif // POINT_H
Merci beaucoup.