为什么C++编译器没有检测到正确声明的类?

Why is the C++ compiler not detecting a properly declared Class?

本文关键字:声明 编译器 C++ 检测 为什么      更新时间:2023-10-16

根据错误代码,编译器(MSVC 2019)未检测到正确声明的类。

在下面的代码中,编译器在UACcDefault类定义中首次提及UACvLogin时停止。

[srcUACcontrollersUACcDefault.h][1]

#ifndef MANAGER_UACCDEFAULT_H
#define MANAGER_UACCDEFAULT_H
#include "src/includes.h"
#include "../views/UACvLogin.h"
#include "../models/UACmUsers.h"
//class UACvLogin;
//class UACmUsers;
class UACcDefault {
public:
UACcDefault();
UACcDefault(int iMaxLogin, UACmUsers* mUsers = nullptr, UACvLogin* viewLogin = nullptr);
virtual ~UACcDefault();
int GetUserid() const;
void SetUserid(int userid);
const wxString& GetUsername() const;
void SetUsername(const wxString& username);
const wxString& GetPassword() const;
void SetPassword(const wxString& password);
int GetContactid() const;
void SetContactid(int contactid);
bool GetLoggedIn();
protected:
private:
UACmUsers* mUsers;
UACvLogin* viewLogin;
int iMaxLogin;
};
#endif //MANAGER_UACCDEFAULT_H

错误消息是:

src/UAC/controllers/UACcDefault.h(19): error C2061: syntax error: identifier 'UACvLogin'
src/UAC/controllers/UACcDefault.h(37): error C2143: syntax error: missing ';' before '*'
src/UAC/controllers/UACcDefault.h(37): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
src/UAC/controllers/UACcDefault.h(37): error C2238: unexpected token(s) preceding ';'

我研究了代码,C2061C2143C4430C2238,它们表明编译器没有检测到UACvLogin已被声明。

每当我采取措施减轻这些错误时,例如更改代码UACvLogin使其不是指针,我都会收到以下错误消息:

src/UAC/controllers/UACcDefault.h(37): error C3646: 'viewLogin': unknown override specifier
src/UAC/controllers/UACcDefault.h(37): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

编译器现在关注变量的名称(viewLogin),而不是类型。如果我从头文件中删除UACvLogin* viewLogin(该变量当前仅在一种方法中使用),或者取消注释class UACvLogin;行,编译器会将其焦点更改为UACmUsers标识符:

src/UAC/controllers/UACcDefault.h(36): error C2143: syntax error: missing ';' before '*'
src/UAC/controllers/UACcDefault.h(36): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
src/UAC/controllers/UACcDefault.h(36): error C2238: unexpected token(s) preceding ';'

如果我取消注释两个类声明,class UACvLogin;class UACmUsers;,编译器会抱怨 SOCI 库。我不会在这里引用错误消息。

我使用/P选项执行了一个构建以查看预处理器输出,并且包含将类声明放在它们应该在的位置:在UACcDefault类中使用/引用它们之前。

有人可以帮助我找到此错误的原因吗?


整个项目都在GitHub上。

  • srcincludes.h
  • ../views/UACvLogin.h=srcUACviewsUACvLogin.h
  • ../models/UACmUsers.h=srcUACmodelsUACmUsers.h
  • cmake-build-debug-msvc-2019/UACvLogin.i10.2MB 此文件显示UACvLogin.cpp的预处理器输出。
  • cmake-build-debug-msvc-2019/UACmUsers.i10.2MB 此文件显示UACmUsers.cpp的预处理器输出。
  • cmake-build-debug-msvc-2019/UACcDefault.i10.2MB 此文件显示UACcDefault.cpp的预处理器输出。

对于循环包含链,标头护罩或类似功能无法按预期工作。问题是头文件A.h需要头文件B.h中的符号x,而头文件B.h需要头文件A.h中的符号y。两者都无法得到他们的意愿,一些头文件将使用另一个文件中的符号,而实际上没有包含其头文件(感谢包含保护)。


让我们举一个简单的例子,使用上面的名字...

第一个头文件A.h

#ifndef A_H
#define A_H
#include "B.h"
struct x
{
y y_member;
};
#endif

然后头文件B.h

#ifndef B_H
#define B_H
#include "A.h"
struct y
{
x x_member;
};
#endif

现在,如果我们通过预处理器A.h运行头文件,则生成的代码将如下所示:

// Included from B.h
struct y
{
x x_member;
};
// Part of A.h itself
struct x
{
y y_member;
};

由于标头包含保护,文件B.h实际上不包含来自A.h的任何内容,这意味着符号x在使用时将是未知的。

如果你删除了标头包含守卫,那么你就会有一个无限的包含"递归",所以这也行不通。


正如我在评论中提到的,您自己已经有了解决方案的开始。修改UACcDefault.h,如下所示:

#ifndef MANAGER_UACCDEFAULT_H
#define MANAGER_UACCDEFAULT_H
#include "src/includes.h"
// Don't include these header files
// #include "../views/UACvLogin.h"
// #include "../models/UACmUsers.h"
// Do these forward declarations
class UACvLogin;
class UACmUsers;
class UACcDefault {
// ... Cut to make it shorter
};
#endif //MANAGER_UACCDEFAULT_H

还要确保src/includes.h文件不包含有问题的文件。

您还应该对UACvLogin.hUACmUsers.h文件进行类似的编辑。

循环#includes来自一个includes.h,其中也包括main.h

includes.h文件包含大多数代码所需的一切:wxWidgets,boost::p ropertytree,SOCI。由于需要访问某些全局变量(首选项),因此还包括main.h

我已将includes.h重构为每个库的单独文件。只有模型(我使用的是模型-视图-控制器架构)需要访问 SOCI。

我已将首选项数据和方法移动到具有静态成员的单独类中。这将清理 MyApp,并消除了包含main.h的需要。我能够简化对每个首选项设置的访问以及读取和写入首选项数据文件。只有这个类需要访问 boost::p ropertytree。