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

error: Class has not been declared despite header inclusion, and the code compiling fine elsewhere

本文关键字:方编译 其他 编译 代码 包含标 错误 未声明      更新时间:2023-10-16

所以我在另一个类中包含一个类,该类不断抛出"错误:'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 4.05 中使用代码块 4.05 和 mingw7 64

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

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

头文件/类中的循环依赖关系,我遇到了相同的错误消息:

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 + %dn", 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 个包含相同标头的单独文件并且您正在执行 gcc *.cpp,我已经看到了这个问题。 发生这种情况是因为 #define 是为整个 gcc 实例定义的,而不仅仅是为每个正在编译的对象文件定义的。

前任。

文件1

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

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

#include <file1.hpp>

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

gcc -Wall *.cpp

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

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

例如:

页眉

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;
}

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

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

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

在您的情况下,您可以在其他一些头文件中定义PROBLEMCLASS_H。结果是您的 cpp 文件将跳过头文件中的定义。换句话说,跳过#include "problemclass.h"行。

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

// 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) {
 //...
}

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。我想这是一个和你类似的问题。

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

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

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

Forward 声明 'ProblemClass' 应该做这件事。前向声明对于解决引发链接器/编译器错误的循环包含是必要的
如果我遇到这种问题,请尽可能浏览标题并制作转发声明,无论如何这都是一个很好的做法。

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

使用#Pragma 一次在A.h级这解决了问题。

相关文章: