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)