错误:尽管包含头,但尚未声明类,并且代码在其他地方编译得很好

时间:2011-07-02 01:02:44

标签: c++ compiler-errors header

所以我有一个类包含在另一个类中,它继续抛出“错误:'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。

10 个答案:

答案 0 :(得分:85)

您似乎在说,您显示的代码实际上并不会产生您遇到问题的编译器错误。所以我们只能猜测。以下是一些可能性:

  • 您可能忘记在使用ProblemClass的文件中包含problemclass.h。
  • 您可能在自己的头文件或您正在使用它的地方错误拼写了ProblemClass的名称。如果它是大写错误,例如编写Problemclass或problemClass而不是ProblemClass,则很难发现。
  • 您可以将包含保护#defines从一个头文件复制粘贴到另一个头文件,然后忘记更改定义的名称。然后只有这两个包含头文件中的第一个才会生效。
  • 您可以将ProblemClass放在命名空间A中,在这种情况下,如果您从命名空间A之外引用它,则必须将ProblemClass称为A :: ProblemClass。
  • 您可能正在使用模板而不期望两阶段查找以it does的方式工作。
  • 您可能拼错了包含中的文件名。如果您在拼写错误的名称下也有该文件的旧版本,则编译器不会报告该错误。
  • 你可以让ProblemClass成为一个只在你包含problemclass.h之后才被定义的宏,在这种情况下,你看到的ProblemClass会被宏预处理器的其他东西取代。
  • 您可以在除problemclass.h之外的头文件中定义ProblemClass,然后problemclass.h实际上定义了其他内容。

  • 答案 1 :(得分:28)

    我的头文件/类中的循环依赖导致了同样的错误消息:

    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’
    

    答案 2 :(得分:2)

    请发布您用于编译的命令。我已经看到过这个问题,如果你有2个单独的文件,包含相同的标题,你正在做一个gcc * .cpp。发生这种情况是因为#define是为整个gcc实例定义的,而不仅仅是为每个正在编译的单个目标文件定义的。

    实施例。

    File1中

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

    然后是两个引用它的独立文件。

    #include <file1.hpp>
    

    尝试同时编译所有cpp文件会导致其中一个cpp文件失败,因为已经定义了FILE1_HPP(导致该cpp文件忽略头文件)。

    gcc -Wall *.cpp
    

    答案是删除#ifndef,或者将每个文件编译成自己的目标文件,然后将它们链接到主应用程序中。

    答案 3 :(得分:1)

    我能想到的唯一一件事会导致基于你所呈现的编译错误,如果PROBLEMCLASS_H以某种方式在头文件之外被重新定义。例如:

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

    您可以尝试的一个想法是不在'aclass.h'中包含'problemclass.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'扩展名)并检查实际发生的情况。这很方便,特别是如果'包括'很多并且很难预测。

    答案 4 :(得分:1)

    我遇到了类似的问题,我花了一段时间才找出原因。

    在您的情况下,您可以在其他一些头文件中定义PROBLEMCLASS_H。 结果是你的cpp文件将跳过头文件中的定义。换句话说,跳过行 ((TextView) jobCategory.getSelectedView().findViewById(R.id.firstName)).setError("Field Required");

    就我而言,我在Linux下使用MingW64。假设我有一个头文件IO.h:

    #include "problemclass.h"

    在我的main.cpp文件中:

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

    cpp文件看起来很无辜。但是,当包含// main.cpp #include <unistd.h> #include "IO.h" int main(int argc, char** argv) { //... } 时,它会秘密地包含MingW提供的unistd.h,并且此/usr/i686-w64-mingw32.static/include/io.h看起来像:

    io.h

    现在您可以看到包含// io.h #ifndef _IO_H_ #define _IO_H_ ... #endif /* End _IO_H_ */ 将导致MingW包含unistd.h,这将隐藏我自己的IO.h.我想这与你的问题类似。

    如果切换包含的顺序(在IO.h之后放置io.h),程序将编译。但这不是一个好建议。我建议您不要使用_IO_H_来保护自己的IO.h。

    要了解如何/为什么包含#include <unistd.h>,我同意@greatwolf,您可以使用PROBLEMCLASS_H输出预处理器输出并手动检查它。检查g++ -E之前包含的文件以及包含的顺序。我希望这可以帮助你解决问题。

    答案 5 :(得分:1)

    对于看到这篇文章并且出现此错误的任何人,我想指出,当我忘记在函数名称之前添加类说明符时,这经常发生在我身上,其中该类函数使用在类的标头中私有定义的东西。

    EG:

    标题

    ORDER BY

    来源(将抛出错误 SomeType_t未定义

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

    来源(固定)

    void SomeFunc()
    {
        SomeType_t dummy = 0;
    }
    

    这是一个愚蠢的,但很容易犯的错误,直到你用自己的头撞在桌子上给自己三次脑震荡后才能看到。

    答案 6 :(得分:0)

    我遇到了同样的问题,并且发现自己做错了什么:按照您的示例,我在AClass中包含了ProblemClass,因此引起了问题。

    答案 7 :(得分:0)

    转发声明'ProblemClass'应该做的事情。前向声明对于解决引发链接程序/编译器错误的循环包含是必需的。
    如果遇到此类问题,请遍历标题并在可能的情况下进行正向声明,这是一个好习惯。

    答案 8 :(得分:0)

    遇到了同样的问题, A.h 包含在 B1.h 和 B2.h 中 B2.h 也包含在 B2.cpp 中

    使用 #pragma once 在A.h班 这解决了问题。

    答案 9 :(得分:-1)

    代码:

    #include <iostream>
    #include <conio.h>
    int main(){
        char c = ' ';
        std::string pw;
        while (c!=13){  // c = 13 is 'Enter' key.
            c = getch();
            if (c!=13){
                pw +=c;
                std::cout << "*";
            }
        }
        std::cout <<"\nPassword is :"  << pw;
    
    }
    

    输出:

    ***********
    Password is :password123