【问题标题】:Using a variable without causing circular dependancy使用变量而不引起循环依赖
【发布时间】:2014-05-05 04:12:44
【问题描述】:

我有 5 组“.h”和“.cpp”文件:

  • Main.cpp
  • Game.h、Game.cpp
  • Parent.h、Parent.cpp
  • Child1.h、Child1.cpp
  • Child2.h、Child2.cpp

Main 不包含类,也不包含头文件 - 并且是应用程序的起点。除其他外,它使用收集的信息初始化“Game”类型的变量“myGame”。

Main.cpp

#include "Game.h"
...
Game myGame(*parameters sent to constructor*)

游戏是我的应用程序的主体。它的标头包括 Child1 和 Child2 并使用这些类型初始化变量。它声明了“游戏”类

Game.h

#pragma once

#include "Child1.h"
#include "Child2.h"

class Game
{
public:
    Game(HWND hWnd, ...);
    ~Game();

    Child1 child1Obj;
    Child2 child2obj[20];
    ...
private:
    ...
};

Parent 泛化了两个子类,并提供了类似的函数和变量。它的标头不包含其他文件。

Parent.h

#pragma once

class Parent
{
public:
    Parent(void);
    ~Parent(void);
    ...
};

Child1 和 Child2 都相似,并且包含父标题。

Child1.h

#pragma once
#include "Parent.h"

class Child1 :
    public Parent
{
public:
    Child1();
    ~Child1();
};

我希望能够在ParentChild1Child2 中使用Game 中包含的数据。

我的第一个猜测是简单地将#include "Game.h" 插入到Parent.h 的顶部,但这样做会导致循环依赖。

接下来,我想只要我想在Game 中使用变量和函数,就必须引用实际的游戏对象myGame.(在Main.cpp 中创建)。但我不知道该怎么做。也许我可以提前在Main.h 文件中声明myGame,如下所示:

Main.h

#pragma once
#include "Game.h"

Game myGame;

但为了做到这一点,我仍然必须使用#include "Game.h",并在我想使用myGame 的文件顶部包含“Main.h” - 导致与相同的循环依赖问题如上所述。

我有什么办法:

  1. 在“Main.h”中声明一个 Game 类型的未初始化 myGame
  2. 使用“Main.cpp”中收集的信息初始化myGame
  3. 通过包含声明 myGame 的文件,在 Parent、Child1 和 Child2 中使用 myGame 而不会导致循环依赖。

我能否在“Main.h”中使用#include "Game.h" 来创建游戏变量,但阻止对包含“Main.h”的文件的包含继承?

【问题讨论】:

  • Parent、Child1、Child2如何使用Game?也许你可以在 Game 中使用 forward decls。
  • MacklinB,当然这种类型的问题在 [C] 和 [C++] 中都会出现。但是,问题代码显然不是[C]。也许您应该考虑编辑您的问题,并删除 [C] 标记?
  • #include "Game.h" 中执行 Parent.cppParent 类定义不能依赖Game,尽管它可以通过前向声明接受指针或引用。当然Parent.cpp中的函数体可以使用完整的Games。

标签: c++ class inheritance include


【解决方案1】:

前向声明 允许引用尚未定义的对象,但没有定义就无法实例化它们。上面写着“我稍后再告诉你”。

非法:

class myGame;  // forward declaration, I'll tell you about this later
class myPlayer
{
public:
  myPlayer();
protected:
  myGame theGame;
}

法律:

class myGame;  // forward declaration, I'll tell you about this later
class myPlayer
{
public:
  myPlayer();
protected:
  myGame* theGame;
}

你在头文件中承诺编译器的“稍后”就是源文件。

myPlayer.cpp:

#inlcude "myPlayer.h"

// Tell the compiler what a myGame is, 
// other than something that can be pointed at
#inlcude "myGame.h" 

myPlayer::myPlayer() :
  theGame(new myGame())
{
}

自然地,一个真正的程序会更加复杂,有构造函数的参数等等。这个演示是关于类的结构、描述它们的文件以及它们的互锁关系。

前向声明的缺点是编译器无法获得有关被前向声明的对象的信息,因此它不能生成一个 - 因此,它不能将一个对象放入另一个对象中。话虽如此,你可以指出一个,因为你已经说过有这样一个东西,你有 - 前向声明,因此用这些东西做事是合法的,比如拿他们的内存地址并因此指向它们,或者参考它们。

当编译器深入到源文件 .cpp 中时,您已经移交了前向声明对象的定义,现在它知道它们是什么以及可以用它们做什么。这就是您可以使用指针或引用执行操作的地方,例如创建 new 或在其上调用函数。

【讨论】:

  • 当我在Parent.h 中有#include "Game.h" 时,这解决了我的200 多个错误,但是当我尝试在我的Parent 类下使用任何类型时会导致错误。 Child1 和 Child2 在我的类声明“'Parent': base class undefined”中也出错了。
  • 您的编辑对我不起作用,因为在 myPlayer.cpp 中创建 myGame 的实例时,我需要传递 myPlayer 中不可用但在 Main 中的 3 个参数。
  • @MaklinB,您在问题中没有提及任何相关内容。也许您想问一个新问题?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 2018-07-03
  • 1970-01-01
  • 2020-03-07
相关资源
最近更新 更多