【问题标题】:cannot forward declare with circular includes不能用循环包含转发声明
【发布时间】:2015-03-07 00:16:21
【问题描述】:

我一直在寻找这个问题的解决方案一段时间,这里的每个答案都有一些不包括头文件的变化,但我似乎已经签约愚蠢并且无法弄清楚......

我有基础 C++ 类 creature,应该在 ladybirdaphid 中实现,但我不断收到 expected class-name before ‘{’ token 错误。

生物.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

蚜虫.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

完整的堆栈跟踪

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 {
                               ^

我已经尝试向前声明Creature 类,但后来我得到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

【问题讨论】:

  • 你不能从不完整的类型派生 - 你需要那个标题。此外,我在您发布的代码中没有看到任何循环包含。
  • cell.h 是否包含aphid.hladybird.h?在这种情况下,由于creature.h 包含cell.h,因此您在声明它之前是从Creature 继承的,并且您不能转发声明您从中继承的类。
  • @LogicStuff 你指的是我试图在AphidLadybird 中转发声明Creature
  • 请发布 board.h 和 cell.h,或者至少是这些文件的包含部分
  • invalid use of incomplete type class 'Creature’ - 显然,您转发了Creature。查看其他评论并检查board.hcell.h 是否包含一些继承自Creature 的类。

标签: c++ oop


【解决方案1】:

在 cell.h 中,您有:

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

class Board;
class Aphid;
class Ladybird;

这没有意义。您首先包含整个类定义,然后再次声明这些类。只需删除 #include 行:

class Board;
class Aphid;
class Ladybird;

在 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);
};

Creature 不在任何地方使用,Cell 仅用于指针。您也可以安全地删除这些 #include 行,并将它们替换为 Cell 的前向声明。

顺便说一句:你应该尽快摆脱你的Cell***,改用std::vector

【讨论】:

    【解决方案2】:

    您的文件中有一个循环的#include 依赖项。
    假设您首先在一些 .cpp 文件中包含“aphid.h”,以下是您要按顺序包含的文件:

    1. creature.h(定义包含保护符号 CREATURE_H_
    2. board.h(来自 bio.h)
    3. cell.h(来自 board.h)
    4. aphid.h(来自 cell.h,由于包含保护而被跳过)
    5. ladybird.h(来自 cell.h)
    6. creature.h(来自ladybird.h,因为包含保护而被跳过

      ->ladybird.h 将无法解析,因为在发生 Ladybird 类声明时尚未定义 Creature:

      class Ladybird : public Creature { ... };
      

    为了解决这个问题,您应该从文件 cell.h 中删除以下行:

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

    这编译得很好,因为您在 cell.h 中使用这些类的唯一方法是使用指向它们的指针,这不需要完整的声明,并且会破坏循环包含。

    出于同样的原因,您可能还应该从该文件中删除#include "board.h"。当您使用它时,您还可以从 board.h 文件中删除 #include "cell.h"

    【讨论】:

    • 这行得通,但它似乎违反直觉,为什么我不应该在单元格中包含头文件?
    • 我要补充一点,在这种情况下,“OK”意味着技术上可行,但不一定是个好主意。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-18
    • 1970-01-01
    相关资源
    最近更新 更多