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

751 views Asked by At

According to the error codes, the compiler (MSVC 2019) is not detecting properly declared classes.

In the following code, the compiler halts at the first mention of UACvLogin in the UACcDefault class definition.

[\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

The error messages are:

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

I researched the codes, C2061, C2143, C4430, C2238, and they indicate the compiler is not detecting that UACvLogin has been declared, earlier.

Whenever I take steps to mitigate these errors, such as change the code so UACvLogin is not a pointer, I get these error messages:

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

The compiler is now focusing on the name (viewLogin) of the variable, instead of the type. If I remove UACvLogin* viewLogin from the header file (the variable is currently used in only one method), or un-comment the class UACvLogin; line, the compiler changes its focus to the UACmUsers identifier:

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

If I un-comment both class declarations, class UACvLogin; and class UACmUsers;, the compiler complains about the SOCI library. I will not quote the error messages, here.

I performed a build with the /P option to see the preprocessor output and the includes are putting the class declarations where they should be: before they are used/referenced in the the UACcDefault class.

Can someone help me find the cause of this error?


The entire project is on GitHub.

2

There are 2 answers

0
J Vines On BEST ANSWER

The circular #includes came from having a includes.h, which also included main.h.

The includes.h file had everything needed by most of the code: wxWidgets, boost::propertytree, SOCI. Due to needing access to some global variables (preferences), main.h was also included.

I have refactored includes.h into separate files for each library. Only the models (I am using Model-View-Controller architecture) need access to SOCI.

I have moved the preferences data and methods to a separate class with static members. This cleans up MyApp and eliminates the need to include main.h. I am able to stream-line access to each preference setting and reading and writing the preferences data file. Only this class needs access to boost::propertytree.

9
Some programmer dude On

For a circular include chain, header guards or similar doesn't work as you expect. The problem is that the header file A.h needs the symbol x from header file B.h, and the header file B.h needs the symbol y from the header file A.h. Both can't get their will, some header file will use the symbol from the other file without its header file actually being included (thanks to the include guards).


Lets make a simple example, using the names from above...

First header file A.h:

#ifndef A_H
#define A_H

#include "B.h"

struct x
{
    y y_member;
};

#endif

Then header file B.h:

#ifndef B_H
#define B_H

#include "A.h"

struct y
{
    x x_member;
};

#endif

Now if we run header file A.h through the preprocessor, the resulting code will be something like this:

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

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

Because of the header include guards, the file B.h doesn't actually contain any contents from A.h, meaning the symbol x will be unknown when it's used.

If you remove the header include guards, then you instead have an infinite "recursion" of inclusion, so that won't work either.


As I mentioned in a comment you already have the beginnings of the solution yourself. Modify UACcDefault.h as follows:

#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

And also make sure that the src/includes.h file doesn't include the offending files.

You should also make similar edits to the UACvLogin.h and UACmUsers.h files.