【问题标题】:Circular dependency of class delclarations类声明的循环依赖
【发布时间】:2014-02-11 03:21:42
【问题描述】:

我有两个具有单独标题的类:class Rendererclass TextureTexture 实例旨在管理驻留在Renderer 的内存池中的一些数据,因此Texture 实例不能独立于Renderer 实例而存在。要获得Texture 实例的句柄,只需使用正确的文件名调用Renderer::loadTexture,然后Renderer 在其数据库中搜索具有匹配文件名的Texture 对象,如果找不到匹配项,则实例化一个新纹理。

//renderer.h
#include "texture.h"
class renderer
{
public:
    Texture* loadTexture(std::string fileName);
private:
    std::map<std::string, Texture*> textureDb;
};

//texture.h
class Texture
{
public:
    Texture(std::string imageFileName);
};

我突然想到,将class Texture 的构造函数设为私有,并将Texture * Renderer::loadTexture(std::string filename) 声明为class Renderer 的朋友是合乎逻辑的:

//renderer.h
#include "texture.h"
class renderer
{
public:
    Texture* loadTexture(std::string fileName);
private:
    std::map<std::string, Texture*> textureDb;
};

//texture.h
class texture;
#include "renderer.h"
class Texture
{
private:
    Texture(std::string imageFileName);
    Texture(const Texture &);
    friend Texture* loadTexture(std::string);
};

但是,只有在包含 renderer.h 之前始终包含 texture.h 时才会编译,因为 class Texture 要求 class Renderer 已经定义。防止这种情况的最佳方法是什么? 两个文件中都有包含保护,但为简洁起见,此处省略。

【问题讨论】:

    标签: c++ friend circular-dependency


    【解决方案1】:

    首先,从上面的代码中,尽可能向前声明。这应该会有所帮助。

    // Renderer.h
    class Texture;
    
    class Renderer {
       ...
    };
    
    // Renderer.cpp
    #include "Renderer.h"
    #include "Texture.h"
    
    ...
    
    // Texture.h
    //class Renderer; // looks like this isn't needed
    
    class Texture {
       ...
    };
    
    // Texture.cpp
    #include "Renderer.h"
    #include "Texture.h"
    
    ...
    

    使用前向声明,您应该有足够的资源在 Renderer 类头中声明指向 Texture 的指针。看起来这就是你现在所需要的;将其余部分推送到 Renderer.cpp。

    接下来,避开朋友;但是,在这种情况下,它可能是可以接受的。

    最后,循环依赖从来都不是一件好事。看看你是否可以稍微改变你的设计。看看是否可以引入接口或抽象基类来打破循环依赖。看起来 Renderer 根本不需要依赖 Texture。

    相反,可以考虑重写 Renderer 以依赖某种 ITexture 接口,然后让 Texture 实现 ITexture:

    class ITexture
    {
       // no data members
       // no method bodies
       // only pure virtual method declarations
    };
    
    class Renderer
    {
    public:
        ITexture* loadTexture(std::string fileName);
    private:
        std::map<std::string, ITexture*> textureDb;
    };
    
    class Texture : public ITexture
    {
       ...
    };
    

    【讨论】:

    • “看看你能不能稍微改变你的设计。”我从字面上接受了这个建议:现在,Texture 类依赖于 Renderer 类,而不是相反,我编写了一个资源管理系统,可以自动处理所有所有权关系和数据加载。
    猜你喜欢
    • 2010-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-08
    • 2012-04-24
    • 2018-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多