web-dev-qa-db-fra.com

erreur: la classe n'a pas été déclarée malgré l'inclusion de l'en-tête, et le code compilant bien ailleurs

J'ai donc une classe incluse dans une autre classe qui continue à générer une erreur de compilation du type "erreur: 'ProblemClass' n'a pas été déclaré. Les fichiers sont configurés de la manière suivante:

#ifndef PROBLEMCLASS_H
#define PROBLEMCLASS_H

#include <iostream>
#include <cmath>

class ProblemClass
{
  public:

    virtual void Init() = 0;
};

#endif

et la classe où l'erreur se produit ressemble à ceci:

#ifndef ACLASS_H
#define ACLASS_H

#include "problemclass.h"

class AClass : public Base
{
  public:

    void DoSomething(ProblemClass* problem);

};

#endif

L'erreur de compilation se produit au niveau de la variable vide Dosomething ();

Je suis conscient que le code ici n'est pas suffisant pour résoudre le problème. J'ai été incapable de créer un exemple minimal capable de le reproduire. Ma question est donc beaucoup plus générale. Quel genre de choses pourrait causer cela? Y a-t-il quelque chose en particulier que je devrais rechercher ou une piste d'enquête que je devrais suivre pour le retrouver?

Ce code compile bien dans une version presque identique du projet.

Toute aide, quelle qu'elle soit, serait grandement appréciée. J'utilise codeblocks 10.05 avec mingw4.4.1 in win 7 64 bit.

37
gj5

Vous semblez dire que le code que vous affichez ne génère pas l'erreur du compilateur avec laquelle vous rencontrez un problème. Donc, nous ne pouvons que deviner. Voici quelques possibilités:

  • Vous auriez peut-être oublié d'inclure problemclass.h à partir du fichier où vous utilisez ProblemClass .
  • Vous pourriez avoir mal orthographié le nom de ProblemClass dans son propre fichier d’en-tête ou à l’endroit où vous l’utilisez. Cela peut être difficile à détecter s’il s’agit d’une erreur de capitalisation telle que l’écriture de Problemclass ou problemClass au lieu de ProblemClass .
  • Vous pourriez avoir copié-collé votre garde d'inclusion #defines d'un fichier d'en-tête à un autre, puis oublié de changer les noms définis. Alors seul le premier de ces deux fichiers d’entête inclus prendrait effet .
  • Vous auriez pu placer ProblemClass dans un espace de noms A, auquel cas vous devez faire référence à ProblemClass en tant que A :: ProblemClass si vous vous y référez depuis l'extérieur de l'espace de noms A .
  • Vous utilisez peut-être des modèles et ne vous attendez pas à ce que la recherche en deux phases fonctionne de la même manière cela fonctionne .
  • Vous auriez pu mal orthographier le nom du fichier dans votre inclusion. Le compilateur ne signalera pas d'erreur à ce sujet si vous disposez également d'une ancienne version de ce fichier sous le nom mal orthographié .
  • Vous auriez pu faire de ProblemClass une macro qui ne soit définie qu'après avoir inclus problemclass.h, auquel cas ce que vous voyez sous la forme ProblemClass est remplacé par autre chose par le préprocesseur de macro .
  • Vous pourriez avoir défini ProblemClass dans un fichier d'en-tête autre que problemclass.h, puis problemclass.h définit en réalité autre chose.

  • 82
    Bjarke H. Roune

    J'ai eu ce même message d'erreur à la suite d'une circulaire dependency dans mes fichiers/classes d'en-tête:

    foo.hpp:

    #ifndef FOO_HPP
    #define FOO_HPP
    
    #include <stdio.h>
    #include "bar.hpp" // <-- here
    
    class Foo {
    public:
        int value = 0;
    
        void do_foo(Bar myBar) {
            printf("foo + %d\n", myBar.value);
        }
    };
    
    #endif //FOO_HPP
    

    bar.hpp:

    #ifndef BAR_HPP
    #define BAR_HPP
    
    #include <stdio.h>
    #include "foo.hpp" // <-- and here
    
    class Bar {
    public: 
        int value = 1;      
    
        void do_bar(Foo myFoo) {
            printf("bar = %d \n", myFoo.value);
        }
    };
    
    #endif //BAR_HPP
    

    La compilation avec: g++ -std=c++11 foo.hpp -o foo a généré le résultat suivant:

    In file included from foo.hpp:5:0:
    bar.hpp:11:15: error: ‘Foo’ has not been declared
    bar.hpp: In member function ‘void Bar::do_bar(int)’:
    bar.hpp:12:32: error: request for member ‘value’ in ‘myFoo’, which is of non-class type ‘int’
    
    28
    Manik

    Veuillez poster la commande que vous utilisez pour la compilation. J'ai vu ce problème si vous avez 2 fichiers distincts qui incluent le même en-tête et que vous faites un gcc * .cpp. Cela se produit parce que #define est défini pour toute l'instance de gcc et pas seulement pour chaque fichier objet compilé.

    Ex. 

    Fichier1

    #ifndef FILE1_HPP
    #define FILE1_HPP 1
    ....
    #endif
    

    Ensuite, deux fichiers distincts qui le référencent.

    #include <file1.hpp>
    

    Si vous essayez de tout compiler en même temps, l'un des fichiers cpp échouera puisque FILE1_HPP était déjà défini (le fichier d'en-tête est donc ignoré pour ce fichier cpp).

    gcc -Wall *.cpp
    

    La solution consiste à supprimer le #ifndef ou à compiler chaque fichier dans ses propres fichiers objet, puis à les lier à votre application principale.

    2
    Suroot

    J'ai rencontré un problème similaire et il m'a fallu un certain temps pour savoir pourquoi.

    Dans votre cas, vous pouvez définir PROBLEMCLASS_H dans d’autres fichiers d’en-tête. La conséquence est que votre fichier cpp ignorera la définition dans le fichier d’en-tête. En d'autres termes, la ligne #include "problemclass.h" est ignorée.

    Dans mon cas, j'utilise MingW64 sous Linux. Disons que j'ai un fichier d'en-tête IO.h:

    // IO.h
    #ifndef _IO_H_
    #define _IO_H_
    
    class A{
    ...
    };
    #endif
    

    Dans mon fichier main.cpp:

    // main.cpp
    #include <unistd.h>
    #include "IO.h"
    int main(int argc, char** argv) {
     //...
    }
    

    Le fichier cpp a l'air innocent. Cependant, lorsque unistd.h est inclus, il inclut secrètement /usr/i686-w64-mingw32.static/include/io.h fourni par MingW, et ce io.h ressemble à ceci:

    // io.h
    #ifndef _IO_H_
    #define _IO_H_
    ...
    #endif /* End _IO_H_ */
    

    Vous pouvez maintenant voir que l'inclusion de unistd.h mènera à l'inclusion io.h de MingW et que cela masquera mon propre IO.h. Je suppose que c'est un problème similaire au vôtre. 

    Si vous changez l'ordre des inclusions (mettez #include <unistd.h> après IO.h), le programme est compilé. Mais ce n'est pas une bonne suggestion. Je vous recommande de ne pas utiliser _IO_H_ pour protéger votre propre IO.h.

    Pour comprendre comment/pourquoi votre PROBLEMCLASS_H est inclus, je souscris à @greatwolf, vous pouvez utiliser g++ -E pour générer la sortie du préprocesseur et l'examiner manuellement. Vérifiez quels fichiers sont inclus avant votre PROBLEMCLASS_H et dans quel ordre ils sont inclus. J'espère que cela peut aider à résoudre votre problème. 

    1
    zhanxw

    À tous ceux qui voient ce message et qui ont cette erreur, je tiens à signaler que cela m’arrive fréquemment lorsque j’oublie d’ajouter le spécificateur de classe avant un nom de fonction, cette fonction utilisant un élément défini en privé dans l’en-tête de la classe.

    PAR EXEMPLE:

    Entête

    class SomeClass
    {
    public:
        void SomeFunc();
    private:
        typedef int SomeType_t;
    };
    

    Source (Lance une erreur SomeType_t n'est pas défini )

    void SomeFunc()
    {
        SomeType_t dummy = 0;
    }
    

    Source (Fixe)

    void SomeClass::SomeFunc()
    {
        SomeType_t dummy = 0;
    }
    

    C'est une erreur stupide, mais très facile à faire et à ne pas voir avant que vous ne vous soyez donné trois commotions en vous frappant la tête contre le bureau.

    1
    L-S

    La seule chose à laquelle je pourrais penser qui pourrait causer l’erreur de compilation basée sur ce que vous avez présenté est si PROBLEMCLASS_H a été redéfini en quelque sorte en dehors du fichier d’en-tête. Comme par exemple:

    //main.cpp
    #define PROBLEMCLASS_H
    #include "aclass.h"
    
    int main() {}
    

    Une idée que vous pouvez essayer est de ne pas inclure 'problemclass.h' dans 'aclass.h' mais de simplement faire une déclaration de ProblemClass à la place. Pour que cela fonctionne, vous devez vous assurer que la définition de AClass ne contient que des références ou des pointeurs vers ProblemClass - vous ne voulez pas que le compilateur essaie de prendre la taille de ProblemClass qui aurait besoin de sa définition complète.

    //aclass.h
    #ifndef ACLASS_H
    #define ACLASS_H
    
    class ProblemClass;
    
    class AClass : public Base
    {
      public:
        void DoSomething(ProblemClass* problem);
    };
    
    #endif
    

    Une autre technique que vous pouvez utiliser pour résoudre ce problème d’en-tête consiste à pré-traiter simplement l’unité de compilation «.cpp» qui pose problème. Ouvrez le fichier de sortie prétraité (généralement l'extension «.i») et inspectez ce qui se passe réellement. C'est pratique, surtout si les "inclus" sont nombreux et difficiles à prévoir.

    1
    greatwolf

    J'ai eu le même problème et j'ai découvert ce que je faisais mal: en suivant votre exemple, j'ai inclus ProblemClass dans AClass, ce qui pose problème.

    0
    Raul Luna