0

I keep getting "Unknown type name 'Life'" in world.h and "Unknown type name 'Life'" and "Unknown type name 'World'" in game.h.

I have a feeling that there might be too many include statements based on other posts but I can't find the solution in this case.

Any help/hints will be greatly appreciated

game.h

#pragma once

#ifndef LIFE_H
#include "life.h"
#define LIFE_H
#endif

#ifndef WORLD_H
#include "world.h"
#define WORLD_H
#endif


class Game {
public:
    // Constructor/destructor
    Game(Life **life, int numLife);
    ~Game();

    void game_loop();
private:
    World * m_world;
    int m_steps;
    bool m_automate;
};

world.h

#pragma once

#ifndef LIFE_H
    #include "life.h"
    #define LIFE_H
#endif

#ifndef WORLD_H
    #include "world.h"
    #define WORLD_H
#endif

class World {
public:
    // Constructor/destructor
    World();
    ~World();

    void print() const;

    bool initLife(Life *life);
    void updateWorld();
private:

    char getNextState(char state, char row, char col, bool toggle) const;

    char **m_grid_1;
    char **m_grid_2;
    bool m_toggle;
};

life.h (without any errors)

#ifndef life_h
#define life_h

#ifndef life_h
    #include "life.h"
    #define life_h
#endif

#ifndef GAME_H
    #include "game.h"
    #define GAME_H
#endif

class Life {
public:

    int getCol() const; // const member functions cannot modify member variables.
    int getRow() const;
    int getHeight() const;
    int getWidth() const;
    char getFromFigure(int r, int c) const;

protected:
    int m_col;
    int m_row;
    int m_height;
    int m_width;
    char **m_sprite;
    World *m_world;
};
#endif
Swift Dev Journal
  • 19,282
  • 4
  • 56
  • 66
xxxx
  • 11
  • 2
  • 2
    Tip: Don't gate your `#include` statements with `#ifndef`, that presumes too much. Just include the file and let the included file wall off its contents if necessary using that approach, or `#pragma once`. You only need one of `#ifndef ...` or `#pragma once`, not both. If `#pragma once` works on your compiler then use that and skip the rest of this cruft. – tadman Sep 24 '20 at 19:35
  • 1
    Why do you have ifdef guards both in each header file ***and*** and in every `#include` statement from other header files that include them? Why does `world.h` `#include`s itself? Why does it include `life.h`? Why does `life.h` include itself? Why does `life.h` include `game.h`? Why doesn't it include `world.h`, since it uses a type declared there? As Mr. Spock would say: none of this is logical. What is ***your*** understanding of what the `#include` statement does? – Sam Varshavchik Sep 24 '20 at 19:36
  • Do you know how #include works? It's not a magic spell, it's automated copy-paste. Which order do you expect the compiler to copy-paste these files in? – user253751 Sep 24 '20 at 19:36
  • Helpful reading (of particular interest here is the bits discussing the preprocessor): [How does the compilation/linking process work?](https://stackoverflow.com/questions/6264249/how-does-the-compilation-linking-process-work) – user4581301 Sep 24 '20 at 19:44

1 Answers1

0

You're effectively taking careful aim and shooting yourself precisely in the foot here:

#ifndef life_h
#define life_h

#ifndef life_h
    #include "life.h"
    #define life_h
#endif

Notice you define the very thing that prevents including your own header file.

This is pretty similar to code like:

int loaded = 1;

if (!loaded) {
  // Why doesn't this run!?
}

If your target compiler(s) support #pragma once then remove all of this and just have #pragma once in each of your header files near the top.

Otherwise you need to gate the files individually, only:

// example.h
#ifndef EXAMPLE_H
#define EXAMPLE_H

...

#endif

Where the name of the #define is derived from the filename and is unique within the entire application.

tadman
  • 208,517
  • 23
  • 234
  • 262
  • Given that `pragma once` is not universally supported nor standardized. I personally wouldn't recommend it. I would stick with plain, old fashioned, header guards - in general. – Jesper Juhl Sep 24 '20 at 19:54
  • @JesperJuhl If the compiler target for this *does* support it then there's no reason to not use it. We're not all writing ultra-portable code. – tadman Sep 24 '20 at 19:54
  • Fair enough. But it *will* potentially bite the day you want to port the code. And writing 3 lines rather than 1 seems a small cost to pay to dodge that potential future problem, with no real downsides. Just my opinion. – Jesper Juhl Sep 24 '20 at 19:57
  • @JesperJuhl It's also possible that by that time we'll have C++ modules and none of this will matter. Premature optimization and premature portability concerns are on the same level. – tadman Sep 24 '20 at 19:58
  • 1
    I guess I'm coloured by working with a codebase that has to support Linux, Solaris, FreeBSD, MacOS & Windows and several compilers; MSVC, GCC, Clang, Solaris Studio. (Which is challenging, but perfectly doable, but one has to be diligent and avoid non-standard stuff and extensions). – Jesper Juhl Sep 24 '20 at 20:01
  • 1
    @JesperJuhl Living the cross-platform dream that is also a nightmare! Thankfully some of the quirkiest "C++" compilers are effectively dead. Pour one out for HP's compiler group. – tadman Sep 24 '20 at 20:02
  • 1
    I think the one that annoyed the most in the past was IBMs xlC. – Jesper Juhl Sep 24 '20 at 20:06
  • @PeteBecker Fair enough, adjusted. – tadman Sep 24 '20 at 21:55