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

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

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

在下面的代码中,编译器在 UACcDefault class 定义中第一次提到 UACvLogin 时停止。

[\src\UAC\controllers\UACcDefault.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 ';'

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

我使用 /P 选项执行构建以查看预处理器输出,并且包含将 class 声明放在它们应该在的位置:在它们 used/referenced 之前UACcDefault class.

谁能帮我找出这个错误的原因?


整个项目都在GitHub

对于循环包含链,header 守卫或类似的东西不会像您预期的那样工作。问题是 header 文件 A.h 需要来自 header 文件 B.h 的符号 x,而 header 文件 B.h需要 header 文件 A.h 中的符号 y。两者都无法实现他们的意愿,一些 header 文件将使用来自另一个文件的符号,而实际上没有包含其 header 文件(感谢包含保护)。


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

第一个 header 文件 A.h:

#ifndef A_H
#define A_H

#include "B.h"

struct x
{
    y y_member;
};

#endif

然后 header 文件 B.h:

#ifndef B_H
#define B_H

#include "A.h"

struct y
{
    x x_member;
};

#endif

现在如果我们 运行 header 通过预处理器文件 A.h ,结果代码将是这样的:

// Included from B.h
struct y
{
    x x_member;
};

// Part of A.h itself
struct x
{
    y y_member;
};

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

如果你删除 header 包含守卫,那么你将拥有一个无限的包含“递归”,所以这也不起作用。


正如我在评论中提到的,您自己已经有了解决方案的开端。修改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::propertytree、SOCI。由于需要访问一些全局变量(首选项),main.h 也被包括在内。

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

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