1

I am designing an abstract particle class for a game I'm writing in C++. Each derived particle class will have a different texture used by all instances of that class. Naturally, I'd like to use static members to store the textures. However, the textures are loaded, unloaded, and drawn identically for every particle. Thus I'd also like to write those functions in the base particle class rather than rewriting them for each derived class. The problem is that there's no way in C++ to create a static, virtual member.

I have found a couple suggestions on related Stack Overflow questions (here, here, and here). The two common suggestions are as follows:

  1. Create a virtual method (say, texture) in the base class that returns a reference to the texture object, and override that method in each derived class.
  2. Use the curiously recurring template pattern to allow me to call the derived class's static member from the base class methods.

These are both good solutions, but neither seems quite ideal for my purposes.

I can't use (2) because since the derived classes don't share a common base class, I can't use polymorphism to store pointers to a mixture of different derived particles. Thus I'd need a separate container for each type of particle I want to add to the scene, which is not very maintainable.

Option (1) works perfectly for the draw function. But as the question title alludes, I don't have an instance variable with which to call texture from the load and unload methods. These methods ought to be static. Both functions are one-liners, so it's not difficult to just write those two functions for each subclass. However, it's a little less safe that way since there's nothing forcing me to implement those functions, even though they ought to be required for each subclass. Also, I'd just like to know if there's a better solution in case I or someone else runs into this issue with a class hierarchy with more complex methods (requiring more code duplication).

It's possible there is no better solution, but I thought I'd ask to see if anyone here can think of one or perhaps explain how I can otherwise improve my design to avoid the issue.

Edit: Here is an example implementation of option (1), since Kerrek SB pointed out my question is lacking code.

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; }
};

Hopefully my example and comments make the problem a little clearer. I'm essentially trying to avoid the boilerplate code imposed by each static method.

Community
  • 1
  • 1
Jonathan Sharman
  • 636
  • 6
  • 16
  • 2
    So much words. So little codes. – Kerrek SB May 25 '14 at 23:05
  • Good point. I've added a basic example implementation of option (1). – Jonathan Sharman May 25 '14 at 23:34
  • A main question is whether loading of texture can seek out the relevant data and load it, or whether data is streamed in so at the appropriate point in the stream load must be called to digest the following data? – Cheers and hth. - Alf May 25 '14 at 23:34
  • Can you defer loading of the textures until the first time there is an instance of the relevant Particle? – harmic May 25 '14 at 23:39
  • Can't you have the Texture initialize itself? Why isn't load() simply the constructor of Texture, and unload() its destructor? – user207421 May 25 '14 at 23:44
  • What differentiates one texture from another? Different Texture - derived classes each tailored for a particular texture type, or a different resource parameter for their load() functions? In both cases, a templated DerivedParticle class that accepts a template parameter defining either the texture class or resource value would specialize the code for each Derived class leaving only the texture-particle definitions to be specified as parent class of each particle sub-class. – DNT May 26 '14 at 00:22
  • @harmic, that is possible, and that might be the best option in my case. – Jonathan Sharman May 26 '14 at 01:09
  • @DNT, the only thing differentiating textures is the name of the file to be loaded. Could you please elaborate on the idea of the templated DerivedParticle class? Would I still be able to define the texture loading/unloading code in the parent class in that scenario? – Jonathan Sharman May 26 '14 at 01:12

1 Answers1

0

First, I would recommend restructuring the Texture class along RAII lines, so that loading of the texture is performed in the constructor, and unloading is performed in the destructor.

Then you would be able to statically initialize the textures. In the implementation (.cpp) file for DerivedParticle you would put:

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

After that the derived particle gets the correct texture loaded during static initialization, and there is no need to call load/unload methods in the first place - which is even better because you avoid the potential for using an uninitialized texture or forgetting to unload one.

This assumes that the texture filename is known at compile time, and also that the order of initialization of the textures vs. other static objects is not important. If not then you could defer initializing the static instance by wrapping it in a function, and replacing all uses of it with calls to this function:

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

See also How do I prevent the "static initialization order fiasco"? in C++ FAQ.

BTW, best not to use identifiers with leading underscores.

Community
  • 1
  • 1
harmic
  • 28,606
  • 5
  • 67
  • 91
  • I use leading underscores for private member data, and it is safe to do so since I (1) use only one underscore, (2) do not use an initial capital, and (3) do not put them in file scope. I use this convention mainly so accessors/mutators can use the same name as the private member. – Jonathan Sharman May 26 '14 at 17:48
  • Because the Texture depends on other static objects, I'd have to use your second solution. I'm a little hesitant to remove the load/unload functions because they give me more control over resource usage. Would you recommend instead using pointers and deleting them/reallocating them when needed? – Jonathan Sharman May 26 '14 at 17:56