Static and inheriting static variables. How does it work?

So I want each class to hold an image unique to that class. The system I have where class instances each load the image separately is inefficient. There's no reason to load the image more than once if all the instances are using the same image. So I figured the variable that holds the image could be static.

My question involves inheritance with static. If a class holds a static variable, but the derived class needs that static variable to hold something different, can I just re-initialize the inherited static variable with a different image? Will that work and let the base and derived class each hold different images with the same static variable?

I might just be misunderstanding static, or maybe there's a better way to do this. Thoughts?
> There's no reason to load the image more than once if all the instances are using the same image.
> So I figured the variable that holds the image could be static.

Yes.


> can I just re-initialize the inherited static variable with a different image?

No. The static member variable in the derived class is a different variable


> Will that work and let the base and derived class each hold different images with the same static variable?

Yes. But it would not be the same static variable; it would be two different variables with the same (unqualified) name.

Keep in mind though, that there is nothing object-oriented about static members. If you need run-time polymorphic behaviour (you probably do), wrap the access to the static variable in a virtual function.

For instance:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
struct image { image( const char* file ) ; void paint( /* ... */ ) const ; /* ... */ } ;

struct base
{
    virtual ~base() {}
    virtual const image& picture() const { return pic ; /* returns base::pic */ }
    // ...

    static const image pic ; // base::pic
    // ...
};

const image base::pic( "base.png" ) ; // defined in base.cc

struct derived : base
{
    virtual const image& picture() const override { return pic ; /* returns derived::pic */ }
    // ...

    static const image pic ; // derived::pic
    // ...
};

const image derived::pic( "derived.png" ) ; // defined in derived.cc


void foo( base& object )
{
    object.picture().paint( /* ... */ ) ; // polymorphic
    // ...
    object.pic.paint( /* ... */ ) ; // monomorphic; always base::pic.paint( /* ... */ )
}
@octagon
If a class holds a static variable, but the derived class needs that static variable to hold something different, can I just re-initialize the inherited static variable with a different image? Will that work and let the base and derived class each hold different images with the same static variable?


A stattic variable of a base class is a common variable for all classes including the base and its derived classes. So if you change the static variablle in an object of some derived class then all other objects of other derived classes including the base class itself will deal with the new value of the static variable.
Id you want that a base class and its derived classes would have different values in a static variable then each class should have its own static variable.
I might just be misunderstanding static, or maybe there's a better way to do this. Thoughts?


JLBorges gives you the static solution. Here is a non static solution. If you find yourself needing to "change" the image in a derived now, whos to say you wont need to add more images as you develop. Most of the time you want the images to act like statics, because you want to avoid the cost of allocating/loading the same images over and over.

One way of "combining" JLBorges method with the flexibility of being able to "change, even if at initialization" this "static" like variable is not to use static variables in your classes. Rather, have the variable be a pointer or reference. Create a Factory, that creates local static objects for the images you will use. Pass a reference to these static objects to the initializes of your base and derived classes.

What this buys you. You still have the advantage of the static variable in that you are not loading it over and over. You can have a reference to a different image in your base/derived1/derivedN if you so choose.

example using JLBorges code from above:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
struct image { image( const char* file ) ; void paint( /* ... */ ) const ; /* ... */ } ;

struct base
{
    base(const image &newPic) : pic(newPic){}
    virtual ~base() {}
    const image &pic ; // base::pic
    // ...
};


struct derived : base
{
    derived(const image &newPic) : base(newPic){}
    // ...
};

enum imagetype{
   //...
};

struct imageFactory
{
   static const image& GetImage(imagetype iType);
};

const image& imageFactory::GetImage(imagetype iType){
   //... parse logic... assume it was parsed to be of "derived" type
   static image someStaticimage("derived.png");
   return someStaticimage;
}

int main(){
   derived obj1(imageFactory::GetImage(derivedtype1);
   base obj2(imageFactory::GetImage(basetype);
   derived2 obj2(imageFactory::GetImage(derivedtype2);
   derivedN objN(imageFactory::GetImage(derivedtypeN);
}


Disclaimer: GetImage was severely simplified, maybe it is broken into named function, maybe helper function are called that create static local object. Also, an alternative is just use pointers, allocating an Image once, using pointers to that memory. The "loading" will be similar to the use of the static factory objects in that you will only allocate once. You will need to clean up the memory from somewhere outside of the object that reference the data.
Last edited on
> You still have the advantage of the static variable in that you are not loading it over and over.
> You can have a reference to a different image in your base/derived1/derivedN if you so choose.

Yes, the flyweight pattern is a more flexible alternative.
http://en.wikipedia.org/wiki/Flyweight_pattern


> Disclaimer: GetImage was severely simplified ... You will need to clean up the memory
> from somewhere outside of the object that reference the data.

GetImage() is extremely simple if we use the standard library.
With a std::shared_ptr<> where the flyweight is used, and a std::weak_ptr<> for the flyweight pool.

For instance, assuming that the image file name makes a suitable key:

1
2
3
4
5
6
7
8
// image.h
struct image 

{
    image( const char* file ) ;

    // ...
};


1
2
3
4
5
6
7
8
// factory.h
#include <memory>
struct image ;

namespace flyweight_factory
{
    std::shared_ptr<image> get_image( const char* file ) ;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//factory.cc
#include "factory.h"
#include "image.h"
#include <map>
#include <string>

namespace flyweight_factory
{
    namespace { std::map< std::string, std::weak_ptr<image> > flyweight_pool ; }

    std::shared_ptr<image> get_image( const char* file )
    {
        auto iter = flyweight_pool.find(file) ;
        if( iter != flyweight_pool.end() && !iter->second.expired() )
             return iter->second.lock() ;
        else
        {
            auto ptr = std::make_shared<image>(file) ;
            flyweight_pool[file] = ptr ;
            return ptr ;
        }
    }
}


And then:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct base
{
    base( const char* image_file = "base.png" )
            : pic( flyweight_factory::get_image(image_file) ) {}
    virtual ~base() {}
    virtual std::shared_ptr<image> picture() const { return pic ; }
    // ...

    protected: std::shared_ptr<image> pic ; 
    // ...
};

struct derived : base
{
    derived( const char* image_file = "derived.png" ) : base(image_file) {}
    // ...
};

// etc 


Last edited on
Topic archived. No new replies allowed.