前置声明和循环依赖

12

我有两个类,Entity和Level。它们都需要访问彼此的方法。因此,使用#include会导致循环依赖的问题。为了避免这种情况,我在Entity.h中尝试前向声明Level:

class Level { };

然而,由于Entity需要访问Level中的方法,但它无法访问这些方法,因为它不知道它们的存在。是否有一种方法可以在不重新声明大部分Level中内容的情况下解决此问题?

2个回答

11

一个正确的前向声明只需要:

class Level;

请注意缺少花括号,这告诉编译器有一个名为Level的类,但没有关于其中内容的信息。您可以自由使用指向此未定义类的指针(Level *)和引用(Level &)。

请注意,您无法直接实例化Level,因为编译器需要知道类的大小才能创建变量。

class Level;

class Entity
{
    Level &level;  // legal
    Level level;   // illegal
};

为了能在Entity的方法中使用Level,最好将Level的方法定义在一个单独的.cpp文件中,并且只在头文件中声明它们。将声明与定义分离是C++中的最佳实践。

// entity.h

class Level;

class Entity
{
    void changeLevel(Level &);
};


// entity.cpp

#include "level.h"
#include "entity.h"

void Entity::changeLevel(Level &level)
{
    level.loadEntity(*this);
}

1
这解决了我的一些问题,但是当我尝试在实体中使用 Level 的方法时,会出现“不允许不完整类型”的错误。编辑:尽管您进行了编辑,但我的指针仍然无法让我访问这些方法,声称它是一个不完整的类型。 - Oracular
我实际上有几乎和你那里一样的东西;该函数在Entity.h中声明,参数为Level &。在定义函数的.cpp文件中,您在其中拥有“level.loadEntity(* this);”的行会将level用红色下划线标出,并显示“不允许不完整类型”的错误。 - Oracular
2
编辑:我不得不在entity.cpp中#include "level.h"。我想如果我不能在entity.h文件中包含它,由于同样的原因,它也不能被包含在.cpp文件中。包含这个修复了问题。谢谢! - Oracular

1

你有两个选择:

  1. 使用指针,这种情况下,你的前向声明应该没问题。
  2. 内联一个类的方法,这种情况下,如果你包含了.h文件,你可以使用另一个类的方法。

个人建议选择第一种方式,更加清晰,并且允许更好的访问。我经常使用shared_ptr,因此不必担心删除...

Entity.h:
class Level;
class Entity {

private:
   Level* m_pLevel;

public:
   bool  CheckLevel ();
   bool WasItThere();


Level.h

class Entity;
class Level {

private:
   Entity* m_pEntity;



    public:
       public bool CheckMyStuff();
       public bool CheckItOut() { return m_pEntity->WasItThere();}
}


Entity.cpp

#include "Level.h"

bool Entity::CheckLevel () {
  return true;
}


bool Entity::CheckLevel() {
   return m_pLevel->CheckMyStuff();
}

bool Entity::WasItThere() {
   return true;
}



Level.cpp

bool Level::CheckMyStuff() { 
    return true;
}

bool Level::CheckItOut() { 
    return m_pEntity->WasItThere();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接