Salut,
Une petite question avant de commencer...
Quand, dans le code, tu mets le commentaire
Doit-on bien comprendre ce que je comprends, à savoir que la définition de la classe maman est dans maman.hpp et que l'implémentation est dans maman.cpp 
Si c'est le cas, je tiens à te rappeler que, pour que les template fonctionnent, il faut que l'implémentation des fonctions soient accessibles au au compilateur lorsqu'il rencontre quelque chose qui les spécialise.
Si tu obtiens une erreur à l'édition de liens (et que j'ai bien compris la signification du commentaire
), c'est normal :
Quand tu définis une classe template, tu dis au compilateur quelque chose comme
Je ne sais pas encore quel type de données je vais manipuler, mais je sais très bien comment je vais les manipuler
Et comme le code binaire qui sera généré par le compilateur dépend du type de la donnée (parce que, pour le compilateur, un type est d'abord et avant tout une information de taille et de décalage à utiliser pour s'assurer que toutes les données sont accessibles), il attendra d'avoir l'information de type pour pouvoir générer le code binaire qui devra être exécuté.
Lorsque tu utilise un entier comme paramètre template, tu dis au compilateur quelque chose comme
Je ne sais pas encore quelle valeur ce sera, mais:
- Ce sera une constante de compilation
- Pour tout N que tu rencontreras, tu créeras un type différent de telle sorte que Maman<N-1> soit différent de Maman<N> et de Maman<N+1>
Du coup, lorsque le compilateur rencontre le code
1 2 3 4 5
| template<int N>
int Maman<N>::GetValue()
{
return N;
} |
Il a beau savoir ce qu'il doit faire, il lui manque quand même une information des plus importantes : quelle valeur doit il donner à N 
Et fatalement, cela l'empêche de générer le code binaire qui correspond, par exemple à Maman<6>.
Le résultat des courses, c'est que, quand dans Fille, il va rencontrer la directive include <Maman.h>, il va copier le contenu du fichier Maman.h à savoir
1 2 3 4 5 6 7 8
| template<int N>
class Maman
{
public:
Maman(const char* uneChaine);
virtual ~Maman();
virtual int GetValue();
}; |
Du coup, vec le code
class Fille : public Maman<6>
Il sait quelle valeur donner à N... Mais il ne dispose pas des instructions qui lui permettent de générer le code binaire pour les fonctions qu'il rencontre : Il sait juste qu'il existe un constructeur prenant une chaine de caractères, un destructeur virtuel et une fonction virtuelle qui s'appelle GetValeur, ce qui lui suffit pour vérifier les différents appels mais qui est insuffisant pour générer le code binaire correspondant.
Au final, tu te retrouves avec d'un coté, un fichier Maman.cpp dans lequel le code binaire des fonctions membres n'a pas été généré (parce qu'il ne savait pas quelle valeur donner à N) et de l'autre, un fichier (simplifions Fille.cpp) dans lequel il aurait pu générer le code binaire correspondant, vu qu'il savait que N valait 6, à condition de savoir quel code il devait mettre en place. Or, il ne dispose pas de cette informaition 
Le compilateur n'est pas assez malin pour se rendre compte de cette situation parce qu'il "oublie" tout ce qu'il a fait à chaque fois qu'il change de fichier d'implémentation, et, pour lui, "tout est pour le mieux".
C'est à ce moment là que l'éditeur de liens prend le relais, et il rencontre donc des symboles qui font référence à Maman<6>::GetValue() (par exemple).
Il va donc chercher dans les différents fichiers objets (les fichiers qui contiennent le code binaire généré par le compilateur) après la partie de code binaire qui correspond à ce symbole. Mais comme il n'a jamais été généré, il ne va évidemment pas le trouver.
L'éditeur de liens n'aura donc pas d'autre choix que de te dire qu'il ne l'a pas trouvé et de sortir sur ce message d'erreur 
En conclusion, et c'est peut être ce qui a surpris white_tentacle, le code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| template<int N>
class Maman
{
public:
Maman(const char* uneChaine);
virtual ~Maman();
virtual int GetValue();
};
template<int N>
Maman<N>::Maman(const char* uneChaine)
{
// do something
}
template<int N>
Maman<N>::~Maman()
{}
template<int N>
int Maman<N>::GetValue()
{
return N;
} |
ne fonctionnera que si tout ce code se trouve dans Maman.hpp
Partager