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

Posted

技术标签:

【中文标题】通过继承共享静态受保护资源【英文标题】:static protected resource shared through inheritance 【发布时间】:2012-06-10 01:33:39 【问题描述】:

为了尝试替换单例模式和通用的“资源管理器”,我提出了一个解决方案。使资源静态和受保护。该资源在继承类的所有子级之间共享。它有效,但我不确定这是否是一个好方法。 这里有一些代码来表达我在做什么(这里的资源是 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;
;

这样我的资源就会被所有的孩子共享,并且只被初始化一次。 替换我将通过引用随处携带的单例或资源管理器是否是一个好的解决方案。 谢谢!

【问题讨论】:

我自己喜欢这个想法,并且正在谷歌上搜索,看看你是否得到了我怀疑的性能提升。每次我看到一个模式,我都会看到一个间接成本。这似乎是一种清除单例恶臭的方法。这将类元数据放在它所属的位置,在类内部。我会进一步说,如果您正在寻找对象创建的性能和灵活性,那么与其他模式一起执行此操作也是一个很好的设计,添加替代工厂作为静态函数以支持具有不同接口的其他模式。通过外部化获得什么好处? 【参考方案1】:

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

你不能在类声明中初始化非常量成员,所以这个。static std::unique_ptr&lt;sf::Texture&gt; m_texture = nullptr; 会产生这样的结果:错误:ISO C++ 禁止非常量静态成员的类内初始化 你必须在你的类的源文件中初始化它,但在类之外。 std::unique_ptr&lt;sf::Texture&gt; 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 语句和函数调用确实会增加开销,但这更易于维护和安全,并且它会在最后一刻真正需要时加载纹理。

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

软件设计很难。我能给出的最好建议是,在设计系统时问自己这个问题,“我需要编写多少行代码才能引入另一个类似的组件”,你的目标应该是尽可能地减少这种情况,即尽可能多地重用尽可能使用您已经创建的内容。

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

【讨论】:

对于您的第一点,我知道这一点,我使用的是 VS2010。这是为了简化,但我像在外面那样初始化指针。对于您的第二点,有道理,谢谢。第三,我不想做一个单例,因为它几乎是一个全球性的,我不喜欢那些。最后,我做这一切是为了学习和获得好的概念,这样我才能变得更好。我想在这种情况下探索单例和资源管理器的其他替代方案。另外,我讨厌复制/粘贴,因为我什么都没学到。 谢谢!我希望更多的程序员会像你一样思考!如果你有少量对象,单例设计模式是可以的,但是一旦对象数量增加,管理它们就变得非常困难,这就是为什么它很少单独使用,很多时候我们借鉴不同设计的想法来实施我们的系统...如果您总是通过 setter/getter 访问您的成员,即使在全局范围内也可以:) 还要研究内聚和耦合。【参考方案2】:

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

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

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

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

【讨论】:

它是静态的这一事实使得我只得到一个对象的初始化,并且只有在它的值为 nullptr 的情况下。它有效,您可以尝试在 if 语句中放入 std::cout&lt;&lt;"Init";,它只会出现一次,即使创建两个 Bar 对象也是如此。 啊。是的。我的错。我错过了if 测试。无论如何,这看起来仍然不是一个好的实现方式。数据成员非常适合派生类。基类通常用于定义接口。我建议你看看 handle-body/pimpl idiom。 这正是我问的原因。它运作良好,但我真的不确定方法。要去看看成语。谢谢。

以上是关于通过继承共享静态受保护资源的主要内容,如果未能解决你的问题,请参考以下文章

为啥Java中允许受保护的静态? [关闭]

如何在子类中访问超类的“受保护的静态”变量,子类位于不同的包中......?

PHP 从静态方法访问对象的受保护属性

“受保护”和“受保护静态”变量有啥区别?

受保护的静态成员变量

受保护的静态方法访问