58

I know there are a couple of similar questions(circular include) out stackoverflow and other websites. But I still can't figure it out and no solutions pop out. So I would like to post my specific one.

I have a Event class who has 2 and actually more subclass, which are Arrival and Landing. The compiler(g++) complains:

g++ -c -Wall -g -DDEBUG Event.cpp -o Event.o
In file included from Event.h:15,
                 from Event.cpp:8:
Landing.h:13: error: expected class-name before ‘{’ token
make: *** [Event.o] Error 1

People said that it's a circular include. The 3 header files(Event.h Arrival.h Landing.h) are as follows:

the Event.h:

#ifndef EVENT_H_
#define EVENT_H_

#include "common.h"
#include "Item.h"
#include "Flight.h"

#include "Landing.h"

class Arrival;

class Event : public Item {
public:
    Event(Flight* flight, int time);
    virtual ~Event();

    virtual void occur() = 0;
    virtual string extraInfo() = 0; // extra info for each concrete event

    // @implement
    int compareTo(Comparable* b);
    void print();

protected:
    /************** this is why I wanna include Landing.h *******************/
    Landing* createNewLanding(Arrival* arrival); // return a Landing obj based on arrival's info

private:
    Flight* flight;
    int time; // when this event occurs

};

#endif /* EVENT_H_ */

Arrival.h:

#ifndef ARRIVAL_H_
#define ARRIVAL_H_

#include "Event.h"

class Arrival: public Event {
public:
    Arrival(Flight* flight, int time);
    virtual ~Arrival();

    void occur();
    string extraInfo();
};

#endif /* ARRIVAL_H_ */

Landing.h

#ifndef LANDING_H_
#define LANDING_H_

#include "Event.h"

class Landing: public Event {/************** g++ complains here ****************/
public:
    static const int PERMISSION_TIME;

    Landing(Flight* flight, int time);
    virtual ~Landing();

    void occur();
    string extraInfo();
};

#endif /* LANDING_H_ */

UPDATE:

I included Landing.h due to Landing's constructor is called in the Event::createNewLanding method:

Landing* Event::createNewLanding(Arrival* arrival) {
    return new Landing(flight, time + Landing::PERMISSION_TIME);
}
draw
  • 4,696
  • 6
  • 31
  • 37

5 Answers5

101

This should be a comment, but comments don't allow multi-line code.

Here's what's happening:

in Event.cpp

#include "Event.h"

preprocessor starts processing Event.h

#ifndef EVENT_H_

it isn't defined yet, so keep going

#define EVENT_H_
#include "common.h"

common.h gets processed ok

#include "Item.h"

Item.h gets processed ok

#include "Flight.h"

Flight.h gets processed ok

#include "Landing.h"

preprocessor starts processing Landing.h

#ifndef LANDING_H_

not defined yet, keep going

#define LANDING_H_

#include "Event.h"

preprocessor starts processing Event.h

#ifndef EVENT_H_

This IS defined already, the whole rest of the file gets skipped. Continuing with Landing.h

class Landing: public Event {

The preprocessor doesn't care about this, but the compiler goes "WTH is Event? I haven't heard about Event yet."

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • @Ben If we use `class Landing` instead of `#include "Landing.h"`, will `Landing` be defined twice? If the preprocessor does not skip `#ifndef LANDING_H_`, how it treats `class Landing`? As defined or not? – Milo Lu Nov 05 '15 at 21:12
  • 2
    @MiloLu: That's why you use a forward declaration `class Landing;` which is not a definition (no body in `{}`). – Ben Voigt Nov 06 '15 at 15:11
32

Replace

#include "Landing.h"

with

class Landing;

If you still get errors, also post Item.h, Flight.h and common.h

EDIT: In response to comment.

You will need to e.g. #include "Landing.h" from Event.cpp in order to actually use the class. You just cannot include it from Event.h

Erik
  • 88,732
  • 13
  • 198
  • 189
  • because I called Landing's constructor: Landing* Event::createNewLanding(Arrival* arrival) { return new Landing(flight, time + Landing::PERMISSION_TIME); } – draw Mar 16 '11 at 01:22
  • 3
    `#include` the needed header files *in your .cpp* not your .h – Erik Mar 16 '11 at 01:23
  • that works. Thank you so much. Another question: does that implies that it's a good practice to always make foreword reference in you header file? – draw Mar 16 '11 at 01:30
  • @draw: It's good practice to forward declare when forward declaration is enough (you only need `Type *` or `Type &`)- in addition to avoiding such circular include problems, this reduces interdependencies in between files, which a.o. reduces compile time. – Erik Mar 16 '11 at 01:34
  • Listen to the comment! Put `#include` in your .cpp, not your .h! That's what fixed it for me. You still need to ensure that your .h files are `#include`d so that ones that are defined by others are lower down. Also, as stated in previous comments, you can use forward declarations of classes to help when anything is circularly defined. – Variadicism Feb 23 '15 at 06:13
  • Add one possible cause if already have the .h file but class name still not recognized: check if there are multiple files with same name. – Summer Apr 05 '17 at 02:17
4

If you forward-declare Flight and Landing in Event.h, then you should be fixed.

Remember to #include "Flight.h" and #include "Landing.h" in your implementation file for Event.

The general rule of thumb is: if you derive from it, or compose from it, or use it by value, the compiler must know its full definition at the time of declaration. If you compose from a pointer-to-it, the compiler will know how big a pointer is. Similarly, if you pass a reference to it, the compiler will know how big the reference is, too.

Andy Finkenstadt
  • 3,547
  • 1
  • 21
  • 25
2

I got the same error with a different problem,

I used namespaces in my headers and forgot the closing bracket and got this cryptic error instead.

Ali80
  • 6,333
  • 2
  • 43
  • 33
2

I know it is a bit late to answer this question, but it is the first entry in google, so I think it is worth to answer it.

The problem is not a coding problem, it is an architecture problem.

You have created an interface class Event: public Item to define the methods which all events should implement. Then you have defined two types of events which inherits from class Event: public Item; Arrival and Landing and then, you have added a method Landing* createNewLanding(Arrival* arrival); from the landing functionality in the class Event: public Item interface. You should move this method to the class Landing: public Event class because it only has sense for a landing. class Landing: public Event and class Arrival: public Event class should know class Event: public Item but event should not know class Landing: public Event nor class Arrival: public Event.

I hope this helps, regards, Alberto

Alberto
  • 71
  • 1
  • 5