Njdart
Njdart

Reputation: 312

cannot forward declare with circular includes

I've been looking for a solution to this problem for a while now, and every answer on here has been some variation on not including header files, but I seem to have contracted the dumb and cant figure it out...

I have the base C++ class creature, that should be implemented in ladybird and aphid, but I keep getting expected class-name before ‘{’ token errors.

creature.h

#ifndef CREATURE_H_
#define CREATURE_H_

#include <iostream>
#include "board.h"
#include "cell.h"

class Creature {
  private:
    int x, y;
  protected:
    Creature(int x, int y);
  public:
    int getX();
    int getY();
    //virtual bool willMove() = 0;
    //virtual void doMove(Board *board) = 0;
    //std::ostream& operator<<(std::ostream &out, Creature &cCreature);
};

#endif

aphid.h:

#ifndef APHID_H_
#define APHID_H_

#include "creature.h"

class Aphid : public Creature {
  public:
    Aphid(int x, int y);
    static float moveProbability;
    static float killProbabllity;
    static float killModifier;
    static float matingProbability;
    //virtual bool willMove();
    //virtual void doMove(Board *board);
};

#endif

ladybird.h:

#ifndef LADYBIRD_H_
#define LADYBIRD_H_

#include "creature.h"

class Ladybird : public Creature {
  public:
    Ladybird(int x, int y);
    static float moveProbability;
    static float directionProbability;
    static float killProbabllity;
    static float matingProbability;
    //virtual bool willMove();
    //virtual void doMove(Board *board);
};

#endif

Full stack trace

g++ src/*.cpp -o out/main.o -Wall -std=c++11 && ./out/main.o
In file included from src/cell.h:8:0,
                 from src/board.h:4,
                 from src/creature.h:5,
                 from src/aphid.h:4,
                 from src/aphid.cpp:2:
src/ladybird.h:6:34: error: expected class-name before ‘{’ token
 class Ladybird : public Creature {
                                  ^
src/cell.cpp: In member function ‘void Cell::simulateMove(Board*)’:
src/cell.cpp:44:19: error: ‘class Aphid’ has no member named ‘willMove’
         if((*it)->willMove()){
                   ^
src/cell.cpp:45:18: error: ‘class Aphid’ has no member named ‘doMove’
           (*it)->doMove(newBoard);
                  ^
In file included from src/cell.h:7:0,
                 from src/board.h:4,
                 from src/creature.h:5,
                 from src/creature.cpp:1:
src/aphid.h:6:31: error: expected class-name before ‘{’ token
 class Aphid : public Creature {
                               ^
In file included from src/cell.h:8:0,
                 from src/board.h:4,
                 from src/creature.h:5,
                 from src/creature.cpp:1:
src/ladybird.h:6:34: error: expected class-name before ‘{’ token
 class Ladybird : public Creature {
                                  ^
In file included from src/cell.h:7:0,
                 from src/board.h:4,
                 from src/creature.h:5,
                 from src/ladybird.h:4,
                 from src/ladybird.cpp:2:
src/aphid.h:6:31: error: expected class-name before ‘{’ token
 class Aphid : public Creature {
                               ^

I've tried forward declaring the Creature class, but then I get invalid use of incomplete type ‘class Creature’

board.h:

#ifndef BOARD_H_
#define BOARD_H_
#include "cell.h"
#include "creature.h"

class Board{
  private:
    Cell ***board; // A 2D ARRAY OF POINTERS, "what if i just add more stars??!" -- Owen G
    int width;
    int height;
  public:
    Board(int width, int height);
    void populate();
    Cell* getCell(int x, int y);
    void print();
    void simulateMove(Board *board);
};

#endif

cell.h:

#ifndef CELL_H_
#define CELL_H_

#include <iostream>
#include <list>
#include "aphid.h"
#include "ladybird.h"
#include "board.h"

class Board;
class Aphid;
class Ladybird;

class Cell{
  private:
    int x, y;
    std::list<Aphid*> aphids;
    std::list<Ladybird*> ladybirds;

  public:
    Cell(int x, int y);
    void addCreature(Aphid *creature);
    void addCreature(Ladybird *creature);
    int getAphidCount();
    int getLadybirdCount();
    void simulateMove(Board *nextGenerationBoard);
};

#endif

Upvotes: 1

Views: 71

Answers (2)

Martin J.
Martin J.

Reputation: 5118

You have a circular #include dependency in your files.
Let's say you start by including "aphid.h" in some .cpp files, here are the files you are going to include in order:

  1. creature.h (defines the include guard symbol CREATURE_H_)
  2. board.h (from creature.h)
  3. cell.h (from board.h)
  4. aphid.h (from cell.h, skipped because of include guard)
  5. ladybird.h (from cell.h)
  6. creature.h (from ladybird.h, skipped because of include guard)

    -> ladybird.h will fail to parse because Creature still hasn't been defined when the Ladybird class declaration occurs:

    class Ladybird : public Creature { ... };
    

In order to fix this, you should remove the following lines from the file cell.h:

#include "aphid.h"
#include "ladybird.h"

This compiles fine because the only way you're using these classes within cell.h is by having pointers to them, which does not require complete declarations, and breaks the circular inclusion.

For the same reason, you should probably also remove #include "board.h" from that file. And while you're at it, you can also remove #include "cell.h" from the board.h file.

Upvotes: 1

Christian Hackl
Christian Hackl

Reputation: 27538

In cell.h, you have:

#include "aphid.h"
#include "ladybird.h"
#include "board.h"

class Board;
class Aphid;
class Ladybird;

This doesn't make sense. You first include the whole class definitions, then declare the classes again. Just remove the #include lines:

class Board;
class Aphid;
class Ladybird;

In board.h, you have:

#include "cell.h"
#include "creature.h"

And then the following class definition:

class Board{
  private:
    Cell ***board; // A 2D ARRAY OF POINTERS, "what if i just add more stars??!" -- Owen G
    int width;
    int height;
  public:
    Board(int width, int height);
    void populate();
    Cell* getCell(int x, int y);
    void print();
    void simulateMove(Board *board);
};

Creature is not used anywhere, and Cell only for pointers. You can safely remove these #include lines as well and replace them with a forward declaration of Cell.

By the way: You should get rid of your Cell*** as soon as possible and use std::vector instead.

Upvotes: 2

Related Questions