在没有实例变量的派生类中初始化“继承的静态成员”

时间:2014-05-25 23:04:53

标签: c++ inheritance static member derived-class

我正在为一个用C ++编写的游戏设计一个抽象的particle类。每个派生的粒子类将具有该类的所有实例使用的不同纹理。当然,我想使用静态成员来存储纹理。但是,每个粒子都会加载,卸载和绘制相同的纹理。因此,我还想在基础粒子类中编写这些函数,而不是为每个派生类重写它们。问题是在C ++中无法创建静态的虚拟成员。

我在相关的Stack Overflow问题(hereherehere)上找到了一些建议。两个常见的建议如下:

  1. 在基类中创建一个虚拟方法(比如texture),该方法返回对纹理对象的引用,并在每个派生类中重写该方法。
  2. 使用curiously recurring template pattern允许我从基类方法中调用派生类的静态成员。
  3. 这些都是很好的解决方案,但对我来说似乎都不是很理想。

    我不能使用(2)因为派生类不共享公共基类,所以我不能使用多态来存储指向不同派生粒子混合的指针。因此,对于我想要添加到场景中的每种类型的粒子,我需要一个单独的容器,这是不可维护的。

    选项(1)适用于draw函数。但正如问题标题所暗示的那样,我没有一个实例变量可以用textureload方法调用unload。这些方法应该是静态的。这两个函数都是单行的,因此为每个子类编写这两个函数并不困难。但是,它的安全性稍微不那么安全,因为没有任何东西迫使我实现这些功能,即使每个子类都需要它们。另外,我想知道是否有更好的解决方案,以防我或其他人遇到这个问题,使用更复杂的方法(需要更多代码重复)的类层次结构。

    可能没有更好的解决方案,但我想我会问这里是否有人可以想到一个,或者解释一下如何改进我的设计以避免这个问题。

    编辑:这是选项(1)的示例实现,因为Kerrek SB指出我的问题是缺少代码。

    class BaseParticle
    {
    public:
        // Cannot declare virtual load and unload methods because they're static.
    
        void draw()
        {
            texture().draw();
        }
    protected:
        virtual Texture& texture() = 0;
    };
    
    class DerivedParticle : public BaseParticle
    {
    public:
        static void load() // Need to reimplement for every other derived class.
        {
            _texture.load();
        }
    
        static void unload() // Need to reimplement for every other derived class.
        {
            _texture.unload();
        }
    private:
        static Texture _texture; // Need to create for every derived class.
    
        virtual Texture& texture() { return _texture; }
    };
    

    希望我的例子和评论能让问题更加清晰。我基本上试图避免每个静态方法强加的样板代码。

1 个答案:

答案 0 :(得分:0)

首先,我建议沿RAII行重构Texture类,以便在构造函数中执行纹理加载,并在析构函数中执行卸载。

然后你就可以静态初始化纹理了。在DerivedParticle的实现(.cpp)文件中,您可以输入:

static Texture DerivedParticle::texture_("derivedtexturefilename");

之后,派生粒子在静态初始化期间获得正确的纹理,并且不需要首先调用加载/卸载方法 - 这更好,因为您可以避免使用未初始化纹理或忘记使用卸载一个。

这假设纹理文件名在编译时是已知的,并且纹理与其他静态对象的初始化顺序并不重要。如果没有,那么你可以通过将静态实例包装在函数中来推迟初始化静态实例,并用对此函数的调用替换它的所有用法:

Texture& DerivedParticle::texture_() {
    static Texture* texture = new Texture(fileName);
    return *texture;
}

另请参阅C ++ FAQ中的How do I prevent the "static initialization order fiasco"?

BTW,best not to use identifiers with leading underscores