6

I have an error that goes like this

    In file included from Level.hpp:12,
                 from main.cpp:4:
Corridor.hpp: In method `void Game::Corridor::update()':
Corridor.hpp:41: invalid use of undefined type `class Game::Level'
Corridor.hpp:13: forward declaration of `class Game::Level'
Corridor.hpp:42: invalid use of undefined type `class Game::Level'
Corridor.hpp:13: forward declaration of `class Game::Level'
Corridor.hpp:43: invalid use of undefined type `class Game::Level'
Corridor.hpp:13: forward declaration of `class Game::Level'
Corridor.hpp:44: invalid use of undefined type `class Game::Level'
Corridor.hpp:13: forward declaration of `class Game::Level'

Corridor and Level are ...

  // Corridor.hpp

#ifndef GAME_CORRIDOR_HPP
#define GAME_CORRIDOR_HPP

#include <Moot/Math.hpp>

//#include <Level.hpp>
#include <GameWindow.hpp>

namespace Game
{
    class Level; // <-- LINE 13

    class Corridor
    {
        static const unsigned int defaultLevelDepth = 800;

        Moot::Math::Vector3D wp1, wp2, wp3, wp4;
        Moot::Math::Vector2D sp1, sp2, sp3, sp4;

        Level * p_level;

    public:

        Corridor(Moot::Math::Vector3D setFirstPoint, Moot::Math::Vector3D setSecondPoint) 
        {
            wp1 = setFirstPoint;
            wp2 = setSecondPoint;

            wp3 = setFirstPoint;
            wp3.z += defaultLevelDepth;

            wp4 = setSecondPoint;
            wp4.z += defaultLevelDepth;
        }


        void update() {

            sp1 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp1); // <- LINE 41 etc.
            sp2 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp2);
            sp3 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp3);
            sp4 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp4);


            //p_level->getLevelCamera();
        }

        void draw()//const
        {
            Moot::Color tempColor;

            windowInstance().graphics().drawQuad( sp1.x, sp1.y, tempColor,
                                                                                sp2.x,sp2.y, tempColor,
                                                                                sp3.x, sp3.y, tempColor,
                                                                                sp4.x,sp4.y, tempColor, 1);
        }


        void setLevel(Level* setLevel) {
            p_level = setLevel;
        }

    };
}

#endif

and

// Level.hpp

#ifndef GAME_LEVEL_HPP
#define GAME_LEVEL_HPP

#include <Moot/Forward.hpp>
#include <Moot/Window.hpp>
#include <Moot/Math.hpp>

#include <GameWindow.hpp>
#include <Camera.hpp>
#include <Corridor.hpp>
#include <Player.hpp>

#include <vector>


namespace Game
{
    class Level
    {

        typedef Corridor* p_corridor;
        typedef std::vector<p_corridor> CorridorList;
        typedef CorridorList::reverse_iterator ReverseCorridorItter;

        CorridorList m_map;
        Camera       m_camera;
        Player         m_player;


    public:

        Level()
        {
            m_player.setLevel(this);

            // Lots of vertices being defined into m_map.


            // Loop through and set camera
            ReverseCorridorItter rit;

            for(rit = m_map.rbegin(); rit != m_map.rend(); rit++)
                (*rit)->setLevel(this);


        }


        ~Level()
        {
            ReverseCorridorItter rit;

            for(rit = m_map.rbegin(); rit != m_map.rend(); rit++) 
                delete (*rit);

            m_map.clear();
        }


        void update() 
        {
            // Temp delete when input and player are implimented.
            if(pad[0].buttons & PAD_UP)
                m_camera.updateTargetOffsets(0, -2);

            if(pad[0].buttons & PAD_DOWN)
                m_camera.updateTargetOffsets(0, 2);

            if(pad[0].buttons & PAD_LEFT)
                m_camera.updateTargetOffsets(-2, 0);

            if(pad[0].buttons & PAD_RIGHT)
                m_camera.updateTargetOffsets(2, 0);

            m_player.update();


            ReverseCorridorItter rit;

            for (rit = m_map.rbegin(); rit != m_map.rend(); rit++)
                (*rit)->update();
        }


        void draw() // const // EH!!! wtf ReverseIter isn't a member
        {
            m_player.draw();


            ReverseCorridorItter rit;

            for (rit = m_map.rbegin(); rit != m_map.rend(); rit++)
                (*rit)->draw();

        }


        Camera& getLevelCamera() {
            return m_camera;
        }

    };
}

#endif

The pointer is being set as far as I can tell, but when I try to access a function from Level, BOOM!

Thanks.

PS: The compiler is gcc 2.95.2 if that makes a difference.

EDIT

Updated with complete code.

  • The Corridor.hpp that you have posted doesn't appear to have 47 lines of code. Also, that is one _old_ version of gcc. – CB Bailey Nov 16 '10 at 17:37
  • What are you doing on line 47 of corridor.hpp? – Benjamin Lindley Nov 16 '10 at 17:37
  • From what I see, you're including level.hpp in corridor.hpp and vice versa, which seems a bit odd. – cadolphs Nov 16 '10 at 17:38
  • @Charles Bailey edited thanks for that. yeah very old gcc can't be helped :( –  Nov 16 '10 at 17:40
  • @Oil Charlesworth sorry my haste, line 47 I try to access a method from the level class will update. –  Nov 16 '10 at 17:41
  • @Lagerbaer :) yep thats me trying everything to get it working :( –  Nov 16 '10 at 17:42
  • "Corridor.hpp" contains code, so it's not just a header file, and the two files #include each other. At a guess I'd say something #includes Level first, then Corridor, so when Level #includes Corridor, Corridor can't #include level and therefore doesn't know what a `Game::Level` is. – Beta Nov 16 '10 at 17:46
  • @Beta only level contains corridor, but I've since removed the corridor including level, and get different errors. –  Nov 16 '10 at 17:55

3 Answers3

11

You are #include-ing Level's complete declaration:

#include <Level.hpp>

...and then you try to forward-declare Level:

namespace Game
{
    class Level;

Don't do this. Choose one or the other. (edit) Or at least put the forward-declaration before the #include-ion of the complete declaration. If all you're doing in game_corridor.hpp is setting pointers to a Level, then a forward declare should do fine. If however you need to call functions on Level from within the HPP file, then you'll need to #include the complete declaration.

EDIT2:

Based on your clarifying edit to your OP, you must #include the complete declaration of Level, and not try to use a forward declaration.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • Yeah I tried that first but get errors invalid use of undefined type `class Game::Level' and forward declaration of `class Game::Level'. I've added it to the post. –  Nov 16 '10 at 17:48
  • @PhilCK: Get rid of the forward declare – John Dibling Nov 16 '10 at 17:54
  • getting rid of the forward gives me loads syntax errors regardless if the Level is included or not. –  Nov 16 '10 at 18:00
  • @PhilCK: Edit your OP with the fist few of these & your edited source code – John Dibling Nov 16 '10 at 18:07
  • I've added the complete source code, with and error, from not including level.hpp in corridor.hpp –  Nov 16 '10 at 18:14
2

If you forward-declare Game::Level then don't #include it. In a not-so-related note, use #include "header.hpp", not #include <header.hpp>.

Edit as per your updates: Bring the definition of Game::Corridor::update() outside the header and into an implementation file. This way the compile need not know anything about Game::Level apart from the fact that it exists and it's a type.

wilhelmtell
  • 57,473
  • 20
  • 96
  • 131
  • 3
    @JohnDibling angle-brackets are meant for system includes; double quotes are meant for user headers. It's not a matter of taste; there are environment variables and defaults that count on this. – wilhelmtell Nov 16 '10 at 17:44
  • @wilhelmtell: I used to think this way, too, and argued with much vigor anyone who did otherwise. Based on things I've read on SO, I came to the conclusion this is wrong. I'll look for some posts. (May take time) – John Dibling Nov 16 '10 at 17:47
  • Here's one: http://stackoverflow.com/questions/3469588/pedantic-what-is-a-source-file-what-is-a-header-not-a-newbie-question – John Dibling Nov 16 '10 at 17:49
  • Here's another reference (external): The JSF coding standards on p. 22 say "The #include directive shall use the notation to include header files." because of "unfortunate divergence in vendor implementations". link: http://www2.research.att.com/~bs/JSF-AV-rules.pdf – John Dibling Nov 16 '10 at 17:54
  • @John, all that is saying is that "" defers to <> if "" doesn't succeed. But it doesn't mean that you should always use <> instead of "". And technically even <> is implementation defined, so it's kind of a wash. – MSN Nov 16 '10 at 17:55
  • So, to sum up. The Standard doesn't say anywhere that <> are meant for system headers and "" is meant for user code. On top of that, compilers tend to interpret "" in different ways, whereas most compilers interpret <> the same way. So in the interest of portable coding, I changed my mind an now *only* use <> – John Dibling Nov 16 '10 at 17:56
  • @John: As David Thornley says in a comment to an answer to that (your) question you linked to: "there is apparently no guarantee that <> will ever look for an actual file". AFAICT, it would be perfectly standards compliant for a compiler to have the set of standard headers hard-coded in and to only look at that set when you use `#include <>`. With such a compiler using `<>` with your own source files would never succeed. – Laurence Gonsalves Nov 16 '10 at 23:06
  • @Laurence: True, but the same is also true for source files, since the Standard never says what a source file is. – John Dibling Nov 16 '10 at 23:17
0

The problem is that Corridor doesn't know what a Level is, because it can't really #include Level.hpp, because Level.hpp is what #included Corridor.hpp.

The underlying problem is that you're trying to #include a source file. The really underlying problem is that you're using #include when you haven't separated your code into source files and header files. Here's how to split it up. (I'm assuming you're familiar with compiling source files into object files, then linking them into executables.)

Corridor.hpp:

#ifndef GAME_CORRIDOR_HPP
#define GAME_CORRIDOR_HPP

#include <Moot/Math.hpp>

#include <Level.hpp>

namespace Game
{
  class Level;

  class Corridor
  {
    static const unsigned int defaultLevelDepth = 800;

    Moot::Math::Vector3D wp1, wp2, wp3, wp4;
    Moot::Math::Vector2D sp1, sp2, sp3, sp4;

    Level * p_level;

  public:

    Corridor(Moot::Math::Vector3D setFirstPoint, Moot::Math::Vector3D setSecondPoint);

    void update();
    void draw();

    void setLevel(Level* setLevel);
  };
}

#endif

Corridor.cpp:

#include "Corridor.hpp"

namespace Game
{
  Corridor::Corridor(Moot::Math::Vector3D setFirstPoint, Moot::Math::Vector3D setSecondPoint) 
  {
    wp1 = setFirstPoint;
    wp2 = setSecondPoint;
    wp3 = setFirstPoint;
    wp3.z += defaultLevelDepth;
    wp4 = setSecondPoint;
    wp4.z += defaultLevelDepth;
  }

  void Corridor::update() 
  {  
    sp1 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp1);
    sp2 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp2);
    sp3 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp3);
    sp4 = p_level->getLevelCamera().convert3DVectorWithScreenAlgorithm(wp4);
  }

  // and so on

}
Beta
  • 96,650
  • 16
  • 149
  • 150