通过继承共享的静态受保护资源

static protected resource shared through inheritance

本文关键字:静态 受保护资源 共享 继承      更新时间:2023-10-16

为了替换单例模式和通用的"资源管理器",我提出了一个解决方案。使资源静态并受到保护。该资源在继承类中的所有子级之间共享。它有效,但我不确定这是否是继续的好方法。这里有一些代码来表达我正在做的事情(这里的资源是sf::Texture):

class Foo {
public:
    Foo() {
        if(m_texture == nullptr) {
            //Création et chargement de la texture
            m_texture = std::unique_ptr<sf::Texture>(new sf::Texture());
            m_texture->loadFromFile("...");
        }
    }
    void draw(sf::RenderWindow& window) = 0;
protected:
    static std::unique_ptr<sf::Texture> m_texture = nullptr;
};
class Bar : public Foo {
public:
    Bar()
        : m_sprite(*m_texture) {}
    void draw(sf::RenderWindow& window) {
        window.draw(m_sprite); 
    }
private:
    sf::Sprite m_sprite;
};

这样,我的资源就由所有子级共享,并且只初始化一次。替换单例或资源管理器是否是一个很好的解决方案,我会通过参考随身携带。谢谢!

从根本上说,您要做的事情是正确的,静态成员将在所有继承的类之间共享(即完全相同),这样您只需要一个实例,它可以为您节省大量内存,但这里有几个问题......我假设你正在使用 g++。

因此,您不能在类声明中初始化非常量成员。

static std::unique_ptr<sf::Texture> m_texture = nullptr;会产生这个:
错误:ISO C++禁止在类内初始化非常量静态成员
您必须在类的源文件中初始化它,但在类外部。 std::unique_ptr<sf::Texture> Foo::m_texture = nullptr;

其次,直接

访问成员字段不会保存,即使在类函数中,也始终使用 setter 和 getter,这使得代码更易于维护。因此,你可以有一个名为getTexture的静态函数

static std::unique_ptr<sf::Texture> getTexture() {
    if(m_texture == nullptr) {
        //Création et chargement de la texture
        m_texture = std::unique_ptr<sf::Texture>(new sf::Texture());
        m_texture->loadFromFile("...");
    }
    return m_texture;
}

虽然 if 语句和函数调用确实会增加开销,但这更易于维护且更安全,并且在真正需要的最后一刻加载纹理。

回到你的问题,单例设计模式非常简单,主要用于节省内存,因为只创建了对象的单个实例:)资源管理器是一个完全不同的野兽,他们的目标是集中加载和管理资源所需的所有操作,将两者结合起来,您将初始化资源管理器的单个实例,然后通过静态成员字段访问它,让所有对象都发出资源请求,这可能是好事也可能坏, 取决于你想要实现的目标。

软件设计很难。我能给出的最好的建议是,在设计系统时问自己,"我必须写多少行代码才能引入另一个类似的组件",你的目标应该是尽可能减少这种情况,即尽可能多地重用你已经创建的东西。

最好的程序员是最懒惰的:)不,我不是说复制/粘贴,应该禁止。

设计看起来很可疑。我认为使用它比更广泛使用的单例模式(带有函数本地静态实例)没有任何优势。你最好在定义时(而不是在Foo的ctor内)使用默认Texture初始化m_texture对象:

static std::unique_ptr<sf::Texture> m_texture( new sf::Texture() );

数据成员非常适合派生类。基类通常用于定义接口。

我建议你将资源管理器类(Foo)分开,而不是从它继承,调用适当的成员函数来获取Texture对象。