[Résolu] Problème de généricité et d'héritage. Un truc m'échappe...

Bonjour à toutes et à tous

J’ai un souci en voulant faire hériter une classe d’une classe générique. Je n’arrive pas à accéder à une méthode de ma classe générique, bien que lors de la définition de l’héritage je la déclare en “public”.

Voici le code, bien sur simplifié par rapport au problème réel, en cinq fichiers (programme principal Test.ino, classe générique List.h et List.cpp, classe Legume et classe Panier, toutes deux dans les fichiers legumes.h et legumes.cpp.

Quelqu’un peut il mettre le doigt sur ce qui produit l’erreur : undefined reference to `List::empty()’ dans le sketch .ino ?

// Fichier test.ino

#include "legumes.h"
#include "Arduino.h"

Panier * p ;    

void setup () {
    Serial.begin(115200);
    p = new Panier () ;
    if (!p->empty()) Serial.println ("Panier non vide") ;
}

void loop () {}
// fichier Lists.h

#ifndef H_LISTS
#define H_LISTS
#include "Arduino.h"

template <class T>
class List  {
  public :
    List <T> () ;
    boolean empty () ;
} ;
#endif
//Fichier Lists.cpp

#include "Lists.h"
#include "Arduino.h"

template <class T>
List<T>::List () {;}

template <class T>
boolean List<T>::empty () {
  return false ;
}
// fichier legumes.h

#ifndef H_LEGUMES
#define H_LEGUMES
#include "Lists.h"

class Legume {
  public :
    Legume () ;
} ;

class Panier : public List <Legume> {
  public :
    Panier () ;
} ;
#endif
// fichier legumes.cpp

#include "legumes.h"

Legume::Legume () {;}

Panier::Panier () : List <Legume> () {;}

J’avance. J’ai tout mis dans un seul fichier .ino, et ça marche !

#include "Arduino.h"

template <class T>
class List  {
  public :
    List <T> () {;}
    boolean empty () { return false ; }
} ;

class Legume {
  public :
    Legume () {;}
} ;

class Panier : public List <Legume> {
  public :
    Panier () : List <Legume> () {;}
} ;

void setup () {
    Serial.begin(115200);
    Panier * p = new Panier () ;
    if (!p->empty()) Serial.println ("Panier non vide") ;
}

void loop () {}

C’est donc le fait de mettre la classe List dans les deux fichiers List.h et List.cpp qui crée l’erreur. Je cible donc le truc sur la ligne "template " qui précède les deux déclarations de méthodes dans le fichier List.cpp. Si je les enlève, ça crée une erreur. Je ne comprends donc toujours pas le mécanisme de ces déclarations de template et de leur héritage.

J'ai trouvé. Il suffit de rajouter un "#include list.cpp" après le "#include list.h". Bizarre car jusqu'ici le include du ".h" suffisait dans tous les cas. Mais... ma classe list ne comprend qu'une classe avec ce fameux "template" et rien d'autre, donc j'en conclus que dans ce cas particulier le linker ne va pas automatiquement chercher le fichier ".cpp" correspondant. Dans l'absence du contenu des méthodes (constructeur et "empty"), bien qu'elles soient déclarées en prototype dans le fichier ".h", il considère qu'elles sont absentes et trouve une erreur si on les appelle. Bizarrement, il a fait "tilt" sur l'appel de la méthode "empty" avant de le faire sur le constructeur. Il vaut mieux ne pas chercher à comprendre... cela me débloque dans le projet et ça suffit. Donc problème ré-so-lu.

Ce n’est pas dû à l’IDE, c’est plus profond que ça ... lisez ceci sur les templates en C++ et surtout la fin

Templates and multiple-file projects
From the point of view of the compiler, templates are not normal functions or classes. They are compiled on demand, meaning that the code of a template function is not compiled until an instantiation with specific template arguments is required. At that moment, when an instantiation is required, the compiler generates a function specifically for those arguments from the template.

When projects grow it is usual to split the code of a program in different source code files. In these cases, the interface and implementation are generally separated. Taking a library of functions as example, the interface generally consists of declarations of the prototypes of all the functions that can be called. These are generally declared in a "header file" with a .h extension, and the implementation (the definition of these functions) is in an independent file with c++ code.

Because templates are compiled when required, this forces a restriction for multi-file projects: the implementation (definition) of a template class or function must be in the same file as its declaration. That means that we cannot separate the interface in a separate header file, and that we must include both interface and implementation in any file that uses the templates.

Since no code is generated until a template is instantiated when required, compilers are prepared to allow the inclusion more than once of the same template file with both declarations and definitions in a project without generating linkage errors.

J-M-L:
Ce n’est pas dû à l’IDE, c’est plus profond que ça ... lisez ceci sur les templates en C++ et surtout la fin

Ah oui en effet. Bon, je vais mettre ma (mes) classe(s) générique(s)dans un fichier unique. Si j'ai bien compris je n'aurai pas besoin d'y séparer le prototype des méthodes "methode() ;" de leur implémentation "classe::methode () {}
Question subsidiaire : du fait de ce mécanisme de compilation "on demand", suis-je obligé de mettre le "#ifndef CE_MODULE" en tête de ce fichier, pour éviter des links multiples ?

Ça ne mange pas de pain de le mettre :slight_smile:

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.