web-dev-qa-db-ja.com

エラー:ヘッダーを含めてもクラスは宣言されていません。コードは他の場所で正常にコンパイルされています

したがって、別のクラスに含まれるクラスがあり、「error: 'ProblemClass'は宣言されていません。

#ifndef PROBLEMCLASS_H
#define PROBLEMCLASS_H

#include <iostream>
#include <cmath>

class ProblemClass
{
  public:

    virtual void Init() = 0;
};

#endif

エラーが発生するクラスは次のようになります。

#ifndef ACLASS_H
#define ACLASS_H

#include "problemclass.h"

class AClass : public Base
{
  public:

    void DoSomething(ProblemClass* problem);

};

#endif

コンパイルエラーはvoid Dosomething()で発生します。

ここのコードは問題を解決するのに十分ではないことを知っています。私はそれを再現できる最小限の例を作成することができませんでした。したがって、私の質問はもっと一般的です。どのようなことがこれを引き起こす可能性がありますか?特に探す必要があるもの、または追跡するために追跡する必要のある行がありますか?

このコードは、ほぼ同じバージョンのプロジェクトで正常にコンパイルされます。

どんなに曖昧であっても、どんな種類の助けも大歓迎です。 Win 7 64ビットでmingw4.4.1でコードブロック10.05を使用しています。

37
gj5

あなたは、あなたが示しているコードが実際に問題を抱えているコンパイラエラーを生成しないと言っているようです。したがって、推測することしかできません。以下にいくつかの可能性を示します。

  • ProblemClassを使用しているファイルからproblemclass.hをインクルードするのを忘れていたかもしれません。
    • 独自のヘッダーファイルまたは使用している場所で、ProblemClassの名前のスペルを間違えた可能性があります。これは、ProblemClassの代わりにProblemclassまたはproblemClassを記述するなどの大文字使用エラーである場合、見つけるのが難しい場合があります。
    • 包含ガード#definesをあるヘッダーファイルから別のヘッダーファイルにコピーアンドペーストして、定義された名前を変更するのを忘れていた可能性があります。その後、これらの2つのヘッダーファイルのうち最初のもののみが有効になります。
    • ProblemClassをネームスペースAに配置することもできます。その場合、ネームスペースAの外部から参照する場合は、ProblemClassをA :: ProblemClassとして参照する必要があります。
    • テンプレートを使用していて、2相ルックアップが it does のように機能することを期待していない可能性があります。
    • インクルードのファイル名のスペルを間違えた可能性があります。スペルミスの名前でそのファイルの古いバージョンもある場合、コンパイラはエラーを報告しません。
    • ProblemClassをproblemclass.hをインクルードした後にのみ定義されるマクロにすることもできます。この場合、ProblemClassとして表示されるものは、マクロプリプロセッサによって他のものに置き換えられます。
    • Problemclass.h以外のヘッダーファイルでProblemClassを定義してから、実際に何かを定義する場合もあります。
  • 88
    Bjarke H. Roune

    ヘッダーファイル/クラスで循環依存関係の結果として同じエラーメッセージが表示されました。

    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
    

    コンパイル:g++ -std=c++11 foo.hpp -o fooは、次の出力をもたらしました。

    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’
    
    31
    Manik

    コンパイルに使用しているコマンドを投稿してください。同じヘッダーを含む2つのファイルがあり、gcc * .cppを実行している場合、この問題が発生します。これは、コンパイルされる個々のオブジェクトファイルだけでなく、gccインスタンス全体に対して#defineが定義されるために発生します。

    例.

    File1

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

    次に、それを参照する2つの個別のファイル。

    #include <file1.hpp>
    

    同時にコンパイルしようとすると、FILE1_HPPがすでに定義されているため、cppファイルの1つが失敗します(そのcppファイルではヘッダーファイルが無視されるため)。

    gcc -Wall *.cpp
    

    答えは、#ifndefを削除するか、各ファイルを独自のオブジェクトファイルにコンパイルしてから、メインアプリケーションにリンクすることです。

    2
    Suroot

    同様の問題を経験しましたが、その理由を見つけるのに時間がかかりました。

    あなたの場合、他のいくつかのヘッダーファイルでPROBLEMCLASS_Hを定義できます。その結果、cppファイルはヘッダーファイルの定義をスキップします。つまり、#include "problemclass.h"行はスキップされます。

    私の場合、LinuxでMingW64を使用しています。 IO.hというヘッダーファイルがあるとします。

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

    私のmain.cppファイルで:

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

    Cppファイルは無害に見えます。ただし、unistd.hが含まれている場合、MingWが提供する/usr/i686-w64-mingw32.static/include/io.hが密かに含まれており、このio.hは次のようになります。

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

    unistd.hを含めると、MingWからio.hが含まれることになります。これにより、独自のIO.hが非表示になります。それはあなたと同じような問題だと思います。

    インクルードの順序を切り替えると(IO.hの後に#include <unistd.h>を置く)、プログラムがコンパイルされます。しかし、これは良い提案ではありません。 _IO_H_を使用して独自のIO.hを保護しないことをお勧めします。

    PROBLEMCLASS_Hがどのように/なぜ含まれているかを理解するために、@ greatwolfに同意します。g++ -Eを使用してプリプロセッサ出力を出力し、手動で調べることができます。 PROBLEMCLASS_Hの前にどのファイルが含まれているか、またそれらが含まれている順序を確認してください。それがあなたの問題の解決に役立つことを願っています。

    1
    zhanxw

    この投稿を見てこのエラーが発生した人には、関数名の前にクラス指定子を追加するのを忘れたときに頻繁に起こることを指摘したいと思います。そのクラス関数はクラスのヘッダーでプライベートに定義されたものを使用します。

    例えば:

    ヘッダ

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

    ソース(エラーをスローしますSomeType_tが定義されていません

    void SomeFunc()
    {
        SomeType_t dummy = 0;
    }
    

    ソース(固定)

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

    これは馬鹿げていますが、本当に簡単な間違いであり、机に頭をぶつけてから3つの脳震盪を与えてから見るまで見ないでください。

    1
    L-S

    あなたが提示したものに基づいてコンパイルエラーを引き起こすと私が考えることができる唯一のものは、PROBLEMCLASS_Hヘッダーファイルの外部で何らかの形で再定義されました。例えば:

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

    あなたが試すことができる一つのアイデアは、 'proclassmclass.h'を 'aclass.h'に含めず、代わりにProblemClassの前方宣言を行うことです。これが機能するためには、AClassの定義にProblemClassへの参照またはポインターのみが含まれていることを確認する必要があります-コンパイラーが、その完全な定義を必要とするProblemClassのサイズを試そうとしてはなりません。

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

    このヘッダーの問題を追跡するために使用できる別の手法は、問題のある '.cpp'コンパイルユニットを前処理することです。前処理された出力ファイル(通常は「.i」拡張子)を開き、実際に何が起こっているのかを調べます。これは、「インクルード」が多数あり、予測が難しい場合に特に便利です。

    1
    greatwolf

    私は同じ問題を抱えていて、私が間違っていたことを発見しました。あなたの例に従って、AClassにProblemClassを含めたので、問題が発生しました。

    0
    Raul Luna