C++ C++;-3个类之间的循环依赖关系

C++ C++;-3个类之间的循环依赖关系,c++,compiler-errors,circular-dependency,C++,Compiler Errors,Circular Dependency,我有三个类,其中两个类相互依赖,另一个类包含指向这两个类的指针: 玩家: #pragma once #include <SFML\Graphics.hpp> #include "RenderableObject.h" //#include "Renderer.h" class Renderer; class Player : public RenderableObject { public: Player(int size, Renderer* renderer);

我有三个类,其中两个类相互依赖,另一个类包含指向这两个类的指针:

玩家:

 #pragma once
#include <SFML\Graphics.hpp>
#include "RenderableObject.h"
//#include "Renderer.h"

class Renderer;
class Player : public RenderableObject
{
public:
    Player(int size, Renderer* renderer);
    ~Player();

    void render();
    void setX(int x);
    void setY(int y);

    int getX();
    int getY();

    void setVelX(float x);
    void setVelY(float y);

    float getVelx();
    float getVely();

    int getSize();

    private:
    int size;
    int x;
    int y;

    float velx;
    float vely;

    Renderer* ren;

};
渲染器:

#pragma once
#include <SFML\Graphics.hpp>
#include "GameManager.h"
#include "Player.h"

class Renderer
{
public:
    Renderer(GameManager* game);
    ~Renderer();
    sf::RenderWindow* getWindow();
    void draw();
    void renderCircle(int size, int x, int y);
    void renderSquare(int size, int x, int y);

private:
    sf::RenderWindow* win;
    GameManager* game;
    Player* ball;
};
#pragma一次
#包括
#包括“GameManager.h”
#包括“Player.h”
类渲染器
{
公众:
渲染器(GameManager*游戏);
~1();
sf::RenderWindow*getWindow();
无效抽取();
空心渲染圆(整数大小、整数x、整数y);
无效渲染正方形(整数大小,整数x,整数y);
私人:
sf::RenderWindow*win;
游戏经理*游戏;
球员*球;
};
我怀疑这里存在某种循环依赖。通过在播放器头文件中添加“class Renderer;”,我成功地将60多个错误减少到了3个。但是,我现在收到了“使用未定义类型”错误

这可能有助于更高层次地了解我想要实现的目标:

GameManager对象应该包含玩家的一个实例(可能更多)。此GameManager对象在子系统(如渲染器)之间共享,因此它们都可以访问相同的资源

渲染器对象应该能够调用播放器对象(从GameManager对象检索)的render()函数,该函数反过来应该调用渲染器对象的renderCircle()对象


我希望这是一个简单的例子,可以重新安排include,而不必重新设计我已经做过的事情。

在头文件中,您只声明作为指针或引用的变量,编译器只需要知道一个类的存在,其他什么都不需要。它不需要知道它有多大,也不需要知道这个类的成员有哪些。因此,提前声明就足够了

但是,在使用变量的源文件中,创建对象并调用成员函数,然后编译器需要完整的定义,这意味着您必须包含整个头文件


将您的代码简化为:

Player.h

#pragma once

class Renderer;

class Player
{
public:
    Player(Renderer*);

private:
    Renderer* ren;
};
游戏经理

#pragma once

class Renderer;

class GameManager
{
public:
    GameManager(Renderer*);

private:
    Renderer* ren;
};
2.h:

#pragma once

class Player;
class GameManager;

class Renderer
{
public:
    Renderer(GameManager*);

private:
    GameManager* game;
    Player* ball;
};
上面的头文件与您已有的头文件大致相同,只是我在
Renderer.h
中使用了前向声明

现在,在
Renderer.cpp
源文件中,实际创建和使用了
Player
GameManager
对象,我们需要头文件中的完整定义:

#include "Renderer.h"
#include "Player.h"
#include "GameManager.h"

Renderer::Renderer(GameManager* game)
    : game(game), ball(new Player)
{
}

// Other functions that calls member function in the `man` and `ball` objects
当然,您需要在
Player.cpp
GameManager.cpp
源文件中包含“Renderer.h”


如果您有其他错误,它们是由于您所做的其他事情造成的,而不是由于循环依赖关系,因为这些依赖关系已通过正向声明得到解决。

在头文件中,您只声明作为指针或引用的变量,编译器只需要知道类存在,其他什么都不知道。它不需要知道它有多大,也不需要知道这个类的成员有哪些。因此,提前声明就足够了

但是,在使用变量的源文件中,创建对象并调用成员函数,然后编译器需要完整的定义,这意味着您必须包含整个头文件


将您的代码简化为:

Player.h

#pragma once

class Renderer;

class Player
{
public:
    Player(Renderer*);

private:
    Renderer* ren;
};
游戏经理

#pragma once

class Renderer;

class GameManager
{
public:
    GameManager(Renderer*);

private:
    Renderer* ren;
};
2.h:

#pragma once

class Player;
class GameManager;

class Renderer
{
public:
    Renderer(GameManager*);

private:
    GameManager* game;
    Player* ball;
};
上面的头文件与您已有的头文件大致相同,只是我在
Renderer.h
中使用了前向声明

现在,在
Renderer.cpp
源文件中,实际创建和使用了
Player
GameManager
对象,我们需要头文件中的完整定义:

#include "Renderer.h"
#include "Player.h"
#include "GameManager.h"

Renderer::Renderer(GameManager* game)
    : game(game), ball(new Player)
{
}

// Other functions that calls member function in the `man` and `ball` objects
当然,您需要在
Player.cpp
GameManager.cpp
源文件中包含“Renderer.h”



如果您还有其他错误,那是因为您做了其他事情,而不是因为循环依赖关系,因为这些问题已经通过转发声明解决了。

在源文件中,您确实包含了所有头文件?这里有很多指针。很有可能,您可以使用与使用
class Render
类似的前向声明替换许多标题。方便阅读:@Someprogrammerdude,我只包含相应的头文件,而不是其他类的头文件。您需要在源文件中包含您使用的所有类的所有头文件。否则,编译器只知道类可能存在于某个地方,如果您想创建该类的对象或在其中调用成员函数,这是不够的。@user4581301,但我们是否仍然会出现“使用未定义类型”错误?在源文件中,您确实包含所有头文件?这里有很多指针。很有可能,您可以使用与使用
class Render
类似的前向声明替换许多标题。方便阅读:@Someprogrammerdude,我只包含相应的头文件,而不是其他类的头文件。您需要在源文件中包含您使用的所有类的所有头文件。否则,编译器只知道类可能存在于某个地方,如果您想创建该类的对象或在其中调用成员函数,这是不够的。@user4581301,但我们不是仍然会出现“使用未定义类型”错误吗?我已经读到循环依赖是不好的。但是,对我来说,让渲染器调用播放器的重写“render”函数(从RenderObject头文件继承)是有意义的。你怎么看?@B4039与循环依赖无关,在我看来这似乎是个好主意。我认为,拥有一个“renderer”类来保存所有“renderable”对象,然后调用这些对象的“render”函数进行实际渲染是很常见的。是的,但是这种特殊的设计模式导致了循环依赖性?@B4039我在前面的评论中所说的有些误导,甚至可能有点错误。。。A“好”(o)