wake-up-neo.com

fehler: Klasse wurde trotz Header-Header nicht deklariert, und der Code wird an anderer Stelle kompiliert

Ich habe also eine Klasse in einer anderen Klasse, die immer einen Kompilierungsfehler des Formulars "error: 'ProblemClass" hat nicht deklariert. Die Dateien sind so eingerichtet:

#ifndef PROBLEMCLASS_H
#define PROBLEMCLASS_H

#include <iostream>
#include <cmath>

class ProblemClass
{
  public:

    virtual void Init() = 0;
};

#endif

und die Klasse, in der der Fehler auftritt, sieht folgendermaßen aus:

#ifndef ACLASS_H
#define ACLASS_H

#include "problemclass.h"

class AClass : public Base
{
  public:

    void DoSomething(ProblemClass* problem);

};

#endif

Der Kompilierungsfehler tritt bei void Dosomething () auf;

Ich bin mir bewusst, dass der Code hier nicht ausreicht, um das Problem zu lösen. Ich konnte kein minimales Beispiel erstellen, das es reproduzieren kann. Meine Frage ist also viel allgemeiner. Welche Dinge könnten das verursachen? Gibt es etwas Besonderes, nach dem ich suchen sollte, oder eine Untersuchungslinie, der ich folgen sollte, um es aufzuspüren?

Dieser Code kompiliert gut in einer nahezu identischen Version des Projekts.

Hilfe jeglicher Art wäre sehr dankbar, egal wie vage. Ich verwende Codeblocks 10.05 mit mingw4.4.1 in Win 7 64 Bit.

37
gj5

Sie scheinen zu sagen, dass der Code, den Sie anzeigen, nicht tatsächlich den Compiler-Fehler erzeugt, mit dem Sie ein Problem haben. Also können wir nur raten. Hier sind einige Möglichkeiten:

  • Möglicherweise haben Sie vergessen, problemclass.h aus der Datei einzuschließen, in der Sie ProblemClass verwenden.
  • Sie haben den Namen von ProblemClass entweder in seiner eigenen Header-Datei oder an der Stelle, an der Sie sie verwenden, falsch geschrieben. Dies kann schwer zu erkennen sein, wenn es sich um einen Fehler in der Großschreibung handelt, beispielsweise Problemclass oder ProblemClass anstelle von ProblemClass .
  • Sie könnten die #defines von Inclusion Guard von einer Header-Datei in eine andere kopiert haben und dann vergessen, die definierten Namen zu ändern. Dann würde nur die erste dieser beiden enthaltenen Header-Dateien wirksam werden.
  • Sie könnten ProblemClass in einen Namespace A platziert haben. In diesem Fall müssen Sie ProblemClass als A :: ProblemClass bezeichnen, wenn Sie von außerhalb des Namespaces A ..__ darauf verweisen.
  • Möglicherweise verwenden Sie Vorlagen und erwarten nicht, dass die zweiphasige Suche so funktioniert wie und zwar .
  • Sie könnten den Dateinamen in Ihrem Include falsch geschrieben haben. Der Compiler meldet keinen Fehler, wenn sich auch eine alte Version dieser Datei unter dem falsch geschriebenen Namen befindet.
  • Sie könnten ProblemClass zu einem Makro gemacht haben, das erst definiert wird, nachdem Sie problemclass.h eingefügt haben. In diesem Fall wird das, was Sie als ProblemClass sehen, durch etwas anderes durch den Makro-Präprozessor ..__ ersetzt.
  • Sie hätten ProblemClass in einer anderen Header-Datei als problemclass.h definieren können, und problemclass.h definiert dann tatsächlich etwas anderes.

  • 82
    Bjarke H. Roune

    Ich habe dieselbe Fehlermeldung aufgrund einer zirkularen Abhängigkeit in meinen Header-Dateien/-Klassen erhalten:

    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
    

    Kompilieren mit: g++ -std=c++11 foo.hpp -o foo ergab folgende Ausgabe:

    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

    Bitte posten Sie den Befehl, den Sie zum Kompilieren verwenden. Ich habe dieses Problem gesehen, wenn Sie zwei separate Dateien haben, die den gleichen Header enthalten und Sie eine gcc * .cpp-Datei ausführen. Dies geschieht, weil #define für die gesamte gcc-Instanz und nicht nur für jede zu kompilierende Objektdatei definiert wird.

    Ex. 

    Datei1

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

    Dann zwei separate Dateien, die darauf verweisen.

    #include <file1.hpp>
    

    Wenn Sie versuchen, alle gleichzeitig zu kompilieren, schlägt eine der cpp-Dateien fehl, da FILE1_HPP bereits definiert wurde (wodurch die Header-Datei für diese cpp-Datei ignoriert wird).

    gcc -Wall *.cpp
    

    Die Antwort besteht entweder darin, das #ifndef zu entfernen oder jede Datei in ihre eigenen Objektdateien zu kompilieren und sie dann mit Ihrer Hauptanwendung zu verknüpfen.

    2
    Suroot

    Ich habe ein ähnliches Problem erlebt und es dauerte eine Weile, bis ich herausgefunden habe, warum.

    In Ihrem Fall können Sie PROBLEMCLASS_H in einigen anderen Header-Dateien definieren. Die cpp-Datei überspringt die Definition in der Header-Datei. Mit anderen Worten wird die Zeile #include "problemclass.h" übersprungen.

    In meinem Fall verwende ich MingW64 unter Linux. Angenommen, ich habe eine Header-Datei IO.h:

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

    In meiner main.cpp-Datei:

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

    Die CPP-Datei sieht unschuldig aus. Wenn jedoch unistd.h enthalten ist, wird /usr/i686-w64-mingw32.static/include/io.h, der von MingW geliefert wird, heimlich eingeschlossen. Dieser io.h sieht folgendermaßen aus:

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

    Jetzt können Sie sehen, dass die Einbeziehung von unistd.h zur Einbeziehung von io.h in MingW führt und dadurch meine eigene IO.h verbergen wird. Ich denke, das ist ein ähnliches Problem wie bei Ihnen. 

    Wenn Sie die Reihenfolge von include ändern (setzen Sie #include <unistd.h> nach IO.h), wird das Programm kompiliert. Dies ist jedoch kein guter Vorschlag. Ich empfehle Ihnen, _IO_H_ nicht zum Schutz Ihrer eigenen IO.h zu verwenden.

    Um zu verstehen, warum/warum Ihr PROBLEMCLASS_H enthalten ist, stimme ich @greatwolf zu. Sie können g++ -E verwenden, um die Ausgabe des Präprozessors auszugeben und sie manuell zu untersuchen. Prüfen Sie, welche Dateien vor Ihrem PROBLEMCLASS_H enthalten sind und in welcher Reihenfolge sie enthalten sind. Ich hoffe, das kann helfen, Ihr Problem zu lösen. 

    1
    zhanxw

    Jedem, der diesen Beitrag sieht und diesen Fehler hat, möchte ich darauf hinweisen, dass mir dies häufig passiert, wenn ich vergessen habe, den Klassenspezifizierer vor einem Funktionsnamen hinzuzufügen, wobei diese Klassenfunktion etwas privat definiertes im Header der Klasse verwendet.

    Z.B:

    Header

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

    Quelle (Wirft Fehler SomeType_t ist nicht definiert )

    void SomeFunc()
    {
        SomeType_t dummy = 0;
    }
    

    Quelle (fest)

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

    Dies ist ein dummer, aber wirklich einfacher Fehler, den Sie nicht machen können und erst sehen, nachdem Sie sich drei Gedanken gemacht haben, als Sie Ihren Kopf gegen den Schreibtisch schlagen.

    1
    L-S

    Die einzige Sache, die ich mir vorstellen könnte, würde den Kompilierfehler auf der Grundlage dessen, was Sie präsentiert haben, verursachen, wenn PROBLEMCLASS_H irgendwie außerhalb der Header-Datei neu definiert wurde. Wie zum Beispiel:

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

    Eine Idee, die Sie versuchen können, besteht darin, 'problemclass.h' nicht in 'aclass.h' einzuschließen, sondern führen Sie stattdessen eine Vorwärtsdeklaration von ProblemClass aus. Damit dies funktioniert, müssen Sie sicherstellen, dass die Definition von AClass nur Verweise oder Zeiger auf ProblemClass enthält. Der Compiler soll nicht versuchen, die Größe von ProblemClass zu verwenden, für die die vollständige Definition erforderlich ist.

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

    Eine andere Technik, mit der Sie dieses Header-Problem aufspüren können, besteht darin, die problematische '.cpp'-Compilationseinheit einfach vorzuverarbeiten. Öffnen Sie die vorverarbeitete Ausgabedatei (in der Regel die Erweiterung ".i") und prüfen Sie, was tatsächlich passiert. Dies ist vor allem dann praktisch, wenn die 'Includes' zahlreich und schwer vorhersagbar sind.

    1
    greatwolf

    Ich hatte das gleiche Problem und habe herausgefunden, was ich falsch gemacht habe: Nach Ihrem Beispiel habe ich ProblemClass in AClass eingefügt und damit das Problem verursacht.

    0
    Raul Luna