Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

User-Created Header Causing C2061: Syntax Error : Identifier 'classname'

So, I sort of expect this to end up being a simple answer, but I've been hacking at it for a while now, and can't seem to fix this issue. So I have a particular class, Intersection, that when included in any other header gives me:

error C2061: syntax error : identifier 'Intersection'

This is my Intersection header:

#ifndef INTERSECTION_H
#define INTERSECTION_H

#include "Coord.h"
#include "Road.h"
#include "TrafficLight.h"

class Intersection {
private:
    int id;
    Coord * midPoint;
    Road * northRoad;
    Road * eastRoad;
    Road * westRoad;
    Road * southRoad;
    TrafficLight * trafficLight;
public:
    Intersection(int, Coord *, Road *, Road *, Road *, Road *);
    ~Intersection();
    void transitionTrafficLight();
    int getId();
    Road * getNorthRoad();
    Road * getEastRoad();
    Road * getWestRoad();
    Road * getSouthRoad();
    TrafficLight * getTrafficLight();
};

#endif

Now, if I attempt to use this class elsewhere, I get the error. For example:

#ifndef ROAD_H
#define ROAD_H

#include "Coord.h"
#include "Intersection.h"
#include <string>

class Road {

public:
    enum LaneCount { TWO_LANE = 2, FOUR_LANE = 4 };
    Road(std::string, Coord *, Coord *, LaneCount, Intersection *, Intersection *, int);
//shortened

Particularly at the Road constructor (and any other classes which reference Intersection). I don't think it's a syntax problem, as Coord is another class, defined in the same manner, and the compiler (VS 2008) doesn't complain about it. It's just Intersection in particular that's giving me this trouble. :/

I'm tagging it homework -- it's what it's for, even though this is just an error I can't get rid of rather than part of the problem.

Thoughts?

like image 315
Kevin Coppock Avatar asked Jun 29 '11 02:06

Kevin Coppock


1 Answers

It looks like the error is that you have two header files that are circularly including one another - intersection.h and road.h. Doing this tends to lead to weird surprises in C++ because of how include guards work. For example, suppose that I have two header files that look like this:

// File: A.h
#ifndef A_Included
#define A_Included

#include "B.h"

class A {};

void MyFunction(B argument);
#endif

and

// File: B.h
#ifndef B_Included
#define B_Included

#include "A.h"

class B {};

void MyOtherFunction(A argument);
#endif

Now, if I try to #include "A.h", then it expands out to

// File: A.h
#ifndef A_Included
#define A_Included

#include "B.h"

class A {};

void MyFunction(B argument);
#endif

When I try expanding out the #include "B.h", I get this:

// File: A.h
#ifndef A_Included
#define A_Included

// File: B.h
#ifndef B_Included
#define B_Included

#include "A.h"

class B {};

void MyOtherFunction(A argument);
#endif

class A {};

void MyFunction(B argument);
#endif

At this point, the preprocessor will again try expanding out A.h, which leads to this:

// File: A.h
#ifndef A_Included
#define A_Included

// File: B.h
#ifndef B_Included
#define B_Included

// File: A.h
#ifndef A_Included
#define A_Included

#include "B.h"

class A {};

void MyFunction(B argument);
#endif

class B {};

void MyOtherFunction(A argument);
#endif

class A {};

void MyFunction(B argument);
#endif

Now, let's see what happens when we resolve all of these weird include guards. The first time we see A, it's expanded out, as is the case when we expand out B for the first time. However, when we see A for the second time, it's not expanded out at all. Thus, after taking out comments and preprocessor directives, we get this resulting code:

class B {};
void MyOtherFunction(A argument);
class A {};
void MyFunction(B argument);

Notice that when MyOtherFunction is declared, A has not yet been declared, and so the compiler reports an error.

To fix this, you can forward-declare A and B in the header files that need them:

// File: A.h
#ifndef A_Included
#define A_Included

class A {};
class B;    // Forward declaration

void MyFunction(B argument);
#endif

and

// File: B.h
#ifndef B_Included
#define B_Included

class B {};
class A;    // Forward declaration

void MyFunction(B argument);
#endif

Now, there are no more circular dependencies. As long as you #include the appropriate header files in the .cpp files, you should be fine.

Hope this helps!

like image 147
templatetypedef Avatar answered Nov 15 '22 19:11

templatetypedef