为什么 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 ';'
我研究了代码,C2061
、C2143
、C4430
、C2238
,它们表明编译器没有检测到 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。
src\includes.h
../views/UACvLogin.h
= src\UAC\views\UACvLogin.h
../models/UACmUsers.h
= src\UAC\models\UACmUsers.h
cmake-build-debug-msvc-2019/UACvLogin.i
10.2MB 此文件显示 UACvLogin.cpp
. 的预处理器输出
cmake-build-debug-msvc-2019/UACmUsers.i
10.2MB 此文件显示 UACmUsers.cpp
. 的预处理器输出
cmake-build-debug-msvc-2019/UACcDefault.i
10.2MB 此文件显示 UACcDefault.cpp
. 的预处理器输出
对于循环包含链,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.h
和 UACmUsers.h
文件进行类似的编辑。
通告 #includes
来自 includes.h
,其中还包括 main.h
。
includes.h
文件包含大部分代码所需的一切:wxWidgets、boost::propertytree、SOCI。由于需要访问一些全局变量(首选项),main.h
也被包括在内。
我已将 includes.h
重构为每个库的单独文件。只有模型(我使用的是模型-视图-控制器架构)需要访问 SOCI。
我已将首选项数据和方法移动到具有静态成员的单独 class。这会清理 MyApp 并消除包含 main.h
的需要。我能够简化对每个首选项设置以及读写首选项数据文件的访问。只有这个 class 需要访问 boost::propertytree.
根据错误代码,编译器 (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 ';'
我研究了代码,C2061
、C2143
、C4430
、C2238
,它们表明编译器没有检测到 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。
src\includes.h
../views/UACvLogin.h
=src\UAC\views\UACvLogin.h
../models/UACmUsers.h
=src\UAC\models\UACmUsers.h
cmake-build-debug-msvc-2019/UACvLogin.i
10.2MB 此文件显示UACvLogin.cpp
. 的预处理器输出
cmake-build-debug-msvc-2019/UACmUsers.i
10.2MB 此文件显示UACmUsers.cpp
. 的预处理器输出
cmake-build-debug-msvc-2019/UACcDefault.i
10.2MB 此文件显示UACcDefault.cpp
. 的预处理器输出
对于循环包含链,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.h
和 UACmUsers.h
文件进行类似的编辑。
通告 #includes
来自 includes.h
,其中还包括 main.h
。
includes.h
文件包含大部分代码所需的一切:wxWidgets、boost::propertytree、SOCI。由于需要访问一些全局变量(首选项),main.h
也被包括在内。
我已将 includes.h
重构为每个库的单独文件。只有模型(我使用的是模型-视图-控制器架构)需要访问 SOCI。
我已将首选项数据和方法移动到具有静态成员的单独 class。这会清理 MyApp 并消除包含 main.h
的需要。我能够简化对每个首选项设置以及读写首选项数据文件的访问。只有这个 class 需要访问 boost::propertytree.