2

I'm aware this question has been asked numerous times but I've tried several suggestions such as checking my spelling, making sure I included the header files, capitalization, etc, but I'm still getting the same error and can't figure out what's triggering it.

When I try to compile Student.h using g++ -c Customer.h I get the error 'Student' does not name a type on the line 'Student student;' for Login.h and I have no idea why. Can anyone try to pinpoint what's causing it? This variable is supposed to represent the student of this login id/account which is supposed to be a pointer to a Student object.

Likewise, when I try to compile Login.h, I get the error 'Login' has not been declared in Customer.h for bool addAcct(Login*) as well as the error 'Login' does not have a type for Login* logins[MAX_LOGINS].

Any help would be appreciated!

Student.h:

#ifndef STUDENT_H
#define STUDENT_H
#define MAX_LOGINS 4
#include <string>
#include "Login.h" 
using namespace std;

class Student{
    public:
        Student(int = 0, string = ""); 
        int getId();
        bool addAcct(Login*);
        void print();
    private:
        int id;
        string name;
        Login* logins[MAX_LOGINS];
        int numberOfLogins;
};
#endif

Login.h

#ifndef LOGIN_H
#define LOGIN_H
#include <string>
#include "Student.h"
using namespace std;

class Login{
    public:
        Login(int = 0, float = 0); 
        int getNumber();
        void setStudent();
        void print();
    private:
        int number;
        Student student;
};
#endif
  • 1
    Cyclic dependency, login.h include student.h which in turn includes login.h. Both your classes need the other class to be declared first, which is obviously an impossible situation. You need to research *forward declarations*. – john Sep 27 '20 at 05:20
  • 1
    In particular since Student is only using Login as a pointer, you can remove #include "login.h" from student.h and replace it with the forward declaration `class Login;` – john Sep 27 '20 at 05:22
  • 1
    More reading [Resolve build errors due to circular dependency amongst classes](https://stackoverflow.com/questions/625799/resolve-build-errors-due-to-circular-dependency-amongst-classes) – user4581301 Sep 27 '20 at 05:23
  • I'm in a situation where both classes have a bidirectional association between them and each class will have instances of the other class. I'll research more about circular dependency problems, thank you! – DavidsDobriks Sep 27 '20 at 05:25
  • Read a [good C++ programming book](https://stroustrup.com/programming.html) and the documentation of your C++ compiler (e.g. [GCC](http://gcc.gnu.org/)...) and debugger (e.g. [GDB](https://www.gnu.org/software/gdb/)...). Compile with `g++ -Wall -Wextra -g` – Basile Starynkevitch Sep 27 '20 at 06:03

1 Answers1

3

Issue here is the circular dependency (as pointed out in the comments), and the problem with that is the processor essentially handles #include statements as sequential text insertions.

For example, when the preprocessor encounters #include "student.h", it goes step by step like:

#ifndef STUDENT_H  // <--- header guard not defined at this point, ok to proceed
#define STUDENT_H  // <--- define header guard first thing in order to prevent recursive includes
#define MAX_LOGINS 4
#include <string>
#include "Login.h"  --->  #ifndef LOGIN_H
                          #define LOGIN_H
                          #include <string>
                          #include "Student.h"  --->  #ifndef STUDENT_H
                                                      // entire body of student.h is skipped over
                                                      // because STUDENT_H header guard is defined
                          using namespace std;  <---  // so processing continues here

                          class Login{
                          // ...
                          Student student;   // <--- error because class Student is not defined
                          };

The solution is to forward declare types which do not require a full definition, instead of #include'ing the respective header.

In this case, class Login has a member Student student; which requires class Student to be fully defined, so login.h must in fact #include "student.h".

However, class Student only carries the Login* logins[MAX_LOGINS]; array of pointers to Login, and a pointer does not require a full definition of the class, but just a forward declaration of the type. Therefore Student.h can be modified to forward declare class Login instead, which removes the circular header dependency and allows the code to compile.

// #include "Login.h"  // <--- full header not required

class Login;           // <--- forward declaration is sufficient
dxiv
  • 16,984
  • 2
  • 27
  • 49