【问题标题】:error: Class has not been declared despite header inclusion, and the code compiling fine elsewhere错误:尽管包含标头,但尚未声明类,并且代码在其他地方编译正常
【发布时间】:2011-09-27 02:58:37
【问题描述】:

所以我有一个包含在另一个类中的类,它不断抛出形式为“错误:'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 位中使用代码块 10.05 和 mingw4.4.1。

【问题讨论】:

  • 检查您的拼写,10 个这些错误中有 9 个是因为您拼写错误的标识符之一。
  • 我已经用一把细齿梳解决了这个问题,并且有一个朋友也看过它,所以我认为拼写不太可能是问题。以及它在一个稍微不同的项目版本中编译良好的事实,其中两个类都存在并且具有相同的关系。
  • 对我来说看起来不错。你是否为 DoSomething 实现了一个主体?
  • 能否给出完整的代码,尤其是坏掉的和“几乎一模一样的版本”的区别?
  • dsomething 的主体已经实现,是的。完整的功能代码将相当大。除了代码标签之外,我还有什么特别的方式可以发布吗?

标签: c++ compiler-errors header


【解决方案1】:

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

例如。

文件1

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

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

#include <file1.hpp>

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

gcc -Wall *.cpp

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

【讨论】:

  • #define 绝对不应该影响其他编译单元(除非也在其他单元中达到)。如果你能重现这个,那将是一个编译器错误。
【解决方案2】:

根据您提供的内容,我唯一能想到的会导致编译错误的是,如果 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' 扩展名)并检查实际发生的情况。这很方便,尤其是在“包含”很多且难以预测的情况下。

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 这是一个很好的列表。但是,我遇到了这个问题,而且我在 ProblemClass.h 的 AClass 中也指定了一个#include。因此,当它编译 ProblemClass.cc 时,它会在处理 ProblemClass.h 标头之前包含这两个标头。我想我会把它添加到列表中。
    • @Homer6 这有时也会发生在我身上。尤其是当我在一个独立项目中开发一些新的代码模块并尝试将其包含在以后的主项目中时。通常需要进行一些重构,而我只是想删除我在独立部分中使用的那些“帮助程序包含”,这将导致这个问题。
    • 应该补充一点:可以有#included 命名空间中的文件A 在头文件中删除(这绝对是愚蠢和无意的),(所以我们将代码注入命名空间@987654342 @) 并且在翻译单元中这段代码需要被称为 A::gaga(),所以编译器会抱怨找不到函数 gaga() !!!
    • +1 表示第三点。我将一个类重构为父类和子类,并在两者中保留原始的#ifndef #define,因此编译器抱怨现在父类中的所有内容都丢失了。谢谢!
    • 当我创建一个与另一个类在创建时具有相同名称的类时遇到了这个问题。它后来被重命名,但标题保护是相同的,因为它们是自动生成的,当我重命名文件时我从没想过要更改它们。
    【解决方案4】:

    由于头文件/类中的循环依赖,我收到了同样的错误消息:

    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’
    

    【讨论】:

    【解决方案5】:

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

    在您的情况下,您可以在其他一些头文件中定义 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 &lt;unistd.h&gt;),程序将编译。但这不是一个好的建议。我建议你不要使用_IO_H_来保护自己的IO.h。

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

    【讨论】:

    • 这是我的情况。头文件 ifndef 中的拼写错误为 ifdef,因此永远不会包含头文件..
    【解决方案6】:

    对于看到这篇文章并遇到此错误的任何人,我想指出,当我忘记在函数名称前添加类说明符时,这种情况经常发生在我身上,其中该类函数使用了类标题中私有定义的内容。

    EG:

    标题

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

    来源(会抛出错误SomeType_t is not defined

    void SomeFunc()
    {
        SomeType_t dummy = 0;
    }
    

    来源(固定)

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

    这是一个愚蠢但很容易犯的错误,直到你的头撞到桌子上造成了三个脑震荡之后才能看到。

    【讨论】:

      【解决方案7】:

      我有同样的问题,我发现我做错了什么:按照你的例子,我在 AClass 中包含了 ProblemClass,从而导致了问题。

      【讨论】:

        【解决方案8】:

        转发声明'ProblemClass'应该做的事情。前向声明对于解决引发链接器/编译器错误的循环包含是必需的。
        如果我遇到这种问题,请检查标题并尽可能进行前向声明,这无论如何都是一个好习惯。

        【讨论】:

          【解决方案9】:

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

          二手 #编译指示一次 在 A.h 类 这解决了问题。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-12-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多