Thread: Compiler says I didn't declare a type, even though I have.

  1. #1
    Registered User
    Join Date
    Jan 2007
    Posts
    11

    Compiler says I didn't declare a type, even though I have.

    I am not new to programming, but I am new to c++, I have a strong Java background. So I am struggling a little bit with some of the more specific syntax (ie required whitespaces at end of file, using * and &)

    If it isn't obvious this is a simple Maze game, there is a maze, and aguy who wants to get from point a to point b (the maze runner)

    When I go to compile, this is the error I get:

    Code:
    <command line>:1:17: warning: ISO C requires whitespace after the macro name
    
    In file included from c:/Users/Danny/dev/NetBeansProjects/MazeGame/Maze.h:13,
    
                     from c:/Users/Danny/dev/NetBeansProjects/MazeGame/Maze.cpp:8:
    
    c:/Users/Danny/dev/NetBeansProjects/MazeGame/MazeRunner.h:27: error: ISO C++ forbids declaration of `Maze' with no type
    
    c:/Users/Danny/dev/NetBeansProjects/MazeGame/MazeRunner.h:27: error: expected `;' before '*' token
    Here is Maze.h
    Code:
    #ifndef _MAZE_H
    #define	_MAZE_H
    
    #include "Tile.h"
    #include "MazeRunner.h"
    #include <vector>
    
    namespace mazegame
    {
    
            class Maze 
            {
            private:
                    unsigned int maze_rows;
                    unsigned int maze_cols;
                    std::vector<std::vector<char> > maze_char;
                    unsigned int starting_location;
            public:
                    Maze(unsigned int _maze_rows, unsigned int _maze_cols);
                    Maze(const Maze& orig);
                    virtual ~Maze();
                    void generateMaze();
                    void clearMaze();
                    void printMaze();
                    std::vector<mazegame::Tile*> getTiles();
                    MazeRunner* getMazeRunner(unsigned short _player_num);
    
    
            };
    };
    
    #endif	/* _MAZE_H */

    and here is MazeRunner.h

    Code:
    #include "Maze.h"
    
    #ifndef _MAZERUNNER_H
    #define	_MAZERUNNER_H
    
    namespace mazegame
    {        
    
            class MazeRunner
            {
            public:
                    enum Input
                    {
                            MOVE_UP,
                            MOVE_DOWN,
                            MOVE_LEFT,
                            MOVE_RIGHT
                    };
            private:
                    Maze* maze;
                    unsigned int xloc;
                    unsigned int yloc;
            public:
                    MazeRunner(unsigned int _xloc, unsigned int _yloc);
                    MazeRunner(const MazeRunner& orig);
                    virtual ~MazeRunner();
                    void processInput(Input input);
                    unsigned int getX();
                    unsigned int getY();
            };
    };
    
    #endif	/* _MAZERUNNER_H */


    I could compile and run my program just fine until I added the below code into MazeRunner.h
    Code:
    #include "Maze.h"
    
    .
    .
    .
    .
    private:
                    Maze* maze;
    which causes the compile error above. I believe I am following everything correctly, and this is pretty much driving me mad.

    Any assistance in helping me find the answer to my problem would be greatly appreciated.

    edit: after looking again, I think the issue might be that I need to include MazeRunner.h in Maze.h and I need to include Maze.h in MazeRunner.h, so one of them (in this case MazeRunner) is being declared before Maze gets the chance because of the order in how the files are included. Though I am not sure how to rectify this.... I think I may have hit a chicken and egg type problem.
    Last edited by misterdanny; 07-28-2009 at 10:48 PM.

  2. #2
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    maze.h includes mazerunner.h and mazerunner.h includes maze.h. This is known as a circular dependency, and it will cause you all sorts of problems like this.

    You can fix this by doing something called a forward declaration:
    Code:
    // Get rid of this include to avoid a circular dependency
    // #include "Maze.h"
    
    #ifndef _MAZERUNNER_H
    #define	_MAZERUNNER_H
    
    // Forward declare Maze so that we can declare it down below
    class Maze;
    
    namespace mazegame
    {        
    
            class MazeRunner
            {
            public:
                    enum Input
                    {
                            MOVE_UP,
                            MOVE_DOWN,
                            MOVE_LEFT,
                            MOVE_RIGHT
                    };
            private:
                    Maze* maze; // We can declare a pointer to a Maze object since we forward declared it up above.
                    unsigned int xloc;
                    unsigned int yloc;
            public:
                    MazeRunner(unsigned int _xloc, unsigned int _yloc);
                    MazeRunner(const MazeRunner& orig);
                    virtual ~MazeRunner();
                    void processInput(Input input);
                    unsigned int getX();
                    unsigned int getY();
            };
    };
    
    #endif	/* _MAZERUNNER_H */
    Now in mazerunner.cpp you can include maze.h, and then use the Maze class normally.

    When you forward declare a class, it means you tell the compiler that this class exists somewhere. You cannot use the class at this point, but you can declare a pointer or reference to a class.

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    It looks like MazeRunner.h includes Maze.h and Maze.h includes MazeRunner.h. That simply will not do. Rather, you need to break this cycle of inclusion with a forward declaration.

    Looking at the MazeRunner class, I see that it only stores a pointer to a Maze. As such, you could declare within the mazegame namespace:
    Code:
    class Maze;
    Then you remove the inclusion of Maze.h, moving it to the source file that contains the function definitions of the MazeRunner class.

    Actually, looking at the Maze class, I see that it too does not actually store a MazeRunner object. Likewise, you can remove the inclusion of MazeRunner.h (moving it to the corresponding source file), and declare in the mazegame namespace:
    Code:
    class MazeRunner;
    By the way, names that begin with an underscore followed by an uppercase letter are reserved to the implementation for any use. Therefore, you might want to rename your inclusion guards from _MAZE_H and _MAZERUNNER_H to say, MAZE_H_ and MAZERUNNER_H_ respectively.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Registered User
    Join Date
    Jan 2007
    Posts
    11
    Ah that seems to have done the trick.

    Would be be considered "ok" If I were to adopt a practice of always writing
    Code:
    class Xxx;
    before the includes of all my header files?

    for instance making Maze.h look like this
    Code:
    #ifndef _MAZE_H
    #define	_MAZE_H
    
    class Maze;
    
    #include "Tile.h"
    #include "MazeRunner.h"
    #include <vector>
    
    
    
    namespace mazegame
    {
    
            class Maze 
            {
            private:
                    unsigned int maze_rows;
                    unsigned int maze_cols;
                    std::vector<std::vector<char> > maze_char;
                    unsigned int starting_location;
            public:
                    Maze(unsigned int _maze_rows, unsigned int _maze_cols);
                    Maze(const Maze& orig);
                    virtual ~Maze();
                    void generateMaze();
                    void clearMaze();
                    void printMaze();
                    std::vector<mazegame::Tile*> getTiles();
                    MazeRunner* getMazeRunner(unsigned short _player_num);
    
    
            };
    };
    
    #endif	/* _MAZE_H */
    Then I wouldn't have to worry about these "circular dependencies".

    or should I only be writing class Maze; in the MazeRunner.h file. or does it not matter?

  5. #5
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> Would be be considered "ok" If I were to adopt a practice of always writing

    It's up to you. It's not a bad idea, naturally.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  6. #6
    Registered User
    Join Date
    Jan 2007
    Posts
    11
    Actually scratch that, it seems my .h files shouldn't be including any files, I should only be making forward dependencies in .h files... then I would include necessary .h files within my .cpp files.

  7. #7
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> Actually scratch that, it seems my .h files shouldn't be including any files, I should only be making forward dependencies in .h files... then I would include necessary .h files within my .cpp files.

    It depends. Sometimes it's necessary, but yes, if it can be avoided then go that route. The main 'rule' for headers is that they shouldn't contain any code (eg: function definitions) except for inline functions. Some people do it anyway, but it's considered bad form.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by misterdanny
    Ah that seems to have done the trick.

    Would be be considered "ok" If I were to adopt a practice of always writing
    Code:
    class Xxx;
    before the includes of all my header files?
    Before or after, it should not matter if those header files were written properly. What matters is that if you do have it, it is before the point where you use the name.

    Quote Originally Posted by misterdanny
    for instance making Maze.h look like this
    The forward declaration of Maze should be within the mazegame namespace. You might still want to take heed my advice concerning _MAZE_H.

    Note that if the MazeRunner class did store an object of the Maze class, or created an object in a function defined in MazeRunner.h that created an object of the Maze class, a forward declaration would not be good enough. You would need to Maze class definition, and so you would include the Maze.h header.
    Last edited by laserlight; 07-28-2009 at 11:14 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Beginner Needs help in Dev-C++
    By Korrupt Lawz in forum C++ Programming
    Replies: 20
    Last Post: 09-28-2010, 01:17 AM
  2. Replies: 3
    Last Post: 04-29-2008, 01:42 PM
  3. Compiler "Warnings"
    By Jeremy G in forum A Brief History of Cprogramming.com
    Replies: 24
    Last Post: 04-24-2005, 01:09 PM
  4. Errors
    By Rhidian in forum C Programming
    Replies: 10
    Last Post: 04-04-2005, 12:22 PM
  5. Warnings, warnings, warnings?
    By spentdome in forum C Programming
    Replies: 25
    Last Post: 05-27-2002, 06:49 PM