Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » initialising static member

Credits go to jmasterx for helping out!
This thread is locked; no one can reply to it. rss feed Print
initialising static member
William Labbett
Member #4,486
March 2004
avatar

hi,

In my code I want to initialise the static member variable bitmap_generator

#SelectExpand
1class Map_Section { 2 3 static ALLEGRO_BITMAP *(*bitmap_generator[NUM_BITMAP_GENERATING_FUNCTIONS])( void ); 4 5 6 7 8 public: 9 10 GRID_SQUARE **gs; 11 12 ALLEGRO_BITMAP **features_bitmaps; 13 14 BITMAP_LIST *shadows_list; 15 16 unsigned char **cdata; 17 18 int w, h; 19 20 Map_Section ( const char *frd_filename, const char *map_bitmap, const char *shadows_list_filename ); 21 22 Map_Section(); 23 24}; 25 26 27 28//I'm trying to do it here : 29 30const ALLEGRO_BITMAP *(*bitmap_generator[NUM_BITMAP_GENERATING_FUNCTIONS])( void ) = 31 32{ 33 get_grass_recangle 34}

...but I need to make sure it's recognised as the member of Map_Section

How would I do this ?
(please)

jmasterx
Member #11,410
October 2009

Usually initializing static members is done like this:

//in hpp
class foo
{
    private:
        static int i;
};

//in cpp
int foo::i = 0;

for an array = {0,0,0,0} should work

William Labbett
Member #4,486
March 2004
avatar

yeah,

reason I'm asking is because I'm not sure where to put the Map_Section::

e.g.

should it go here :

const ALLEGRO_BITMAP *(Map_Section ::*bitmap_generator[NUM_BITMAP_GENERATING_FUNCTIONS])( void ) =

(which doesn't look right) ?

jmasterx
Member #11,410
October 2009

I found this:
//in cpp
int (Sample::*ptr2)(int, int);

also it should not be const in the cpp since it is not const in your hpp

William Labbett
Member #4,486
March 2004
avatar

Thanks for that.

I've tried it and it works.

Thanks for spotting the unnecessary const

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

William Labbett
Member #4,486
March 2004
avatar

Thanks.

#SelectExpand
1class Map_Section { 2 3 static ALLEGRO_BITMAP *(*bitmap_generator)(); 4 5 6 7 8 public: 9 10 GRID_SQUARE **gs; 11 12 ALLEGRO_BITMAP **features_bitmaps; 13 14 BITMAP_LIST *shadows_list; 15 16 unsigned char **cdata; 17 18 int w, h; 19 20 Map_Section ( const char *frd_filename, const char *map_bitmap, const char *shadows_list_filename ); 21 22 Map_Section(); 23 24}; 25 26 27 28ALLEGRO_BITMAP *(Map_Section::*bitmap_generator)( void ) = 29{ 30 get_grass_rectangle 31};

I get an error for this code :

C:\game_project_jan2011\rabbitsgame>mingw32-make
g++ -c -g -Wshadow -I h_files -I h_files/main_world -Ih_files/helper_functions -
I h_files/cloisters_headers c_files/main/run_game.cpp -o object_files/run_game.
o
In file included from h_files/main_world/land.h:9:0,
from c_files/main/run_game.cpp:9:
h_files/main_world/map_section.h:95:1: error: cannot convert 'ALLEGRO_BITMAP* (*
)()' to 'ALLEGRO_BITMAP* (Map_Section::*)()' in initialization
c_files/main/run_game.cpp: In constructor 'Game::Game()':
c_files/main/run_game.cpp:127:4: error: 'show_through_bitmaps' was not declared
in this scope
mingw32-make: *** [object_files/run_game.o] Error 1

C:\game_project_jan2011\rabbitsgame>PAUSE
Press any key to continue . . .

obviously something's wrong.

Any ideas ?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

I think that this :

ALLEGRO_BITMAP *(Map_Section::*bitmap_generator)( void ) = {get_grass_rectangle};

should be this :

ALLEGRO_BITMAP* (*Map_Section::bitmap_generator)() = get_grass_rectangle;

Give that a whirl...

compiler said:

error: 'show_through_bitmaps' was not declared in this scope

This means you probably forgot to include the classes scope in the definition of the function.

class A {
private :
   int member;
public :
   void DoStuff();
};

void DoStuff() {member = 5;}// error, member not declared in this scope
void A::DoStuff() {member = 5;}// fine

anonymous
Member #8025
November 2006

int (Sample::*ptr2)(int, int);

This should be a pointer-to-member-function type. What you seem to want is an array of pointers to free functions. It appears that the class name should go right in front of the variable name.

ALLEGRO_BITMAP (*Map_Section::bitmap_generator[NUM_BITMAP_GENERATING_FUNCTIONS])( void )

I dropped one pointer as I don't see what exactly that would be for.

Anyway, as always, to avoid going crazy with the declaration syntax, you'd bring in typedefs.

#SelectExpand
1struct X { 2 typedef int (*fun_type)(); 3 static fun_type functions[2]; 4}; 5 6int foo() { return 1;} 7int bar() { return 2;} 8 9//I'm trying to do it here : 10 11X::fun_type X::functions[2] = 12 13{ 14 &foo, &bar 15}; 16 17int main() 18{ 19 return X::functions[0](); 20}

William Labbett
Member #4,486
March 2004
avatar

Give that a whirl...

Thanks, that worked. I thought it looked wrong. I suppose such an initialisation always has to be

classname::variablename

/* edit */

@anonymous

Do you really have to take the address of those functions ?

ie &foo and &bar ?

Aren't foo and bar already pointer values ?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Do you really have to take the address of those functions ?

No. Either way works, you can use the names themselves, or their address.

Similarly, you can call a function pointer by using a dereference, or by using the name itself :

#SelectExpand
1#include <cstdio> 2 3void foo(int a) { 4 printf("%i\n" , a); 5} 6 7int main(int argc , char** argv) { 8 void (*foopointer)(int) = foo; 9 void (*foopointer)(int) = &foo; 10 11 (*foopointer)(10); 12 foopointer(12); 13 14 return 0; 15}

William Labbett
Member #4,486
March 2004
avatar

wow, interesting.

Just to be clear about something else :

anonymous said:

int (Sample::*ptr2)(int, int);

This should be a pointer-to-member-function type.

So that's valid C++ but

what kind declaration would it have to have in the class itself ?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

what kind declaration would it have to have in the class itself ?

#SelectExpand
1 2class Test { 3public : 4 typedef void (Test::* VoidTestMemberVoidFunc) ();// The space after the * is important 5 6private : 7 VoidTestMemberVoidFunc vtmvf; 8 9 void Foo() {printf("Foo.\n");} 10 void Bar() {printf("Bar.\n");} 11 12public : 13 void UseFoo() {vtmvf = &Test::Foo;}// You must use & here 14 void UseBar() {vtmvf = &Test::Bar;}// You must use & here 15 16 void FooBar() {(this->*vtmvf)();} 17 18 Test() : vtmvf(&Test::Foo) {} 19}; 20 21int main(int argc , char** argv) { 22 Test t; 23 t.FooBar(); 24 t.UseBar(); 25 t.FooBar(); 26 27 return 0; 28}

So a pointer to a member function is like this :

ReturnType (ClassName::* FunctionPointerName)(Parameter List);

and you would set and call it like this :

ClassName Object;
ClassName* ObjectPointer = &Object;
FunctionPointerName = &ClassName::FunctionName;

(Object.*FunctionPointerName)(Parameters);
(ObjectPointer->*FunctionPointerName)(Parameters);

All that said, I had to do a little testing before I got it right, and I've also never had a use for this kind of obscure C++ yet.

William Labbett
Member #4,486
March 2004
avatar

brilliant.

Think I just need the static array of function pointers for the moment.

Thanks once more, for clearing that up.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

William Labbett
Member #4,486
March 2004
avatar

but what are you going to use a static array of member function pointers for?

I'm using a static array of function pointers. (note the difference).

It's a long story.

I've got a file which has lots of what I call feature representations in.

Each one has a bunch of data :

a name for a png bitmap which is the feature itself.
type, altitude, and lots of other data.

Now, if the type is SHOW_THROUGH_GENERATED then the feature has no bitmap associated
with it - which otherwise would be loaded and assign to an ALLEGRO_BITMAP * in an array.

Instead, the ALLEGRO_BITMAP * in that array is assigned to by calling a function which returns an ALLEGRO_BITMAP *.

In this case, since the png bitmap filename data for this feature isn't used to load a bitmap, it's used instead to specify which function to call.

So for example, one of the features is a grass bitmap which is generated with some code and is got by calling get_grass_bitmap(). So the program sees it's type is SHOW_THROUGH_GENERATED, looks at the string normally used to load a bitmap, sees it's "GRASS" and passes this to a function which returns an index for the

array of function pointers which will be the function get_grass_bitmap().

Manage to make any sense of that? :)

/* edit : sorry if that's far too obscure */

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

I'm using a static array of function pointers. (note the difference).

Noted, I just wasn't sure because you were asking about member function pointers.

William Labbett said:

Instead, the ALLEGRO_BITMAP * in that array is assigned to by calling a function which returns an ALLEGRO_BITMAP *.

In this case, since the png bitmap filename data for this feature isn't used to load a bitmap, it's used instead to specify which function to call.

Okay, I see what you are doing now. It makes sense. So your ALLEGRO_BITMAP* functions are for creating and drawing a new bitmap, right?

Question - are you using a std::map<string , ALLEGRO_BITMAP*(*)()> to return the function pointer? std::map implements a binary search for you, and that way you don't have to mess around with a linear search for the entry that matches your string.

#SelectExpand
1typedef ALLEGRO_BITMAP* (*TILEMAKERFUNC)(); 2 3ALLEGRO_BITMAP* MakeGrassTile() {/*...*/} 4ALLEGRO_BITMAP* MakeSandTile() {/*...*/} 5ALLEGRO_BITMAP* MakeWaterTile() {/*...*/} 6 7map<string , TILEMAKERFUNC> tilefuncmap; 8 9tilefuncmap["Grass"] = MakeGrassTile; 10tilefuncmap["Sand"] = MakeSandTile; 11tilefuncmap["Water"] = MakeWaterTile; 12 13ALLEGRO_BITMAP* MakeTile(string tilename) { 14 map<string , TILEMAKERFUNC>::iterator it = tilefuncmap.find(tilename); 15 if (it != tilefuncmap.end()) { 16 return (it->second)(); 17// return (tilefuncmap[tilename])(); 18 } 19 return 0; 20}

William Labbett
Member #4,486
March 2004
avatar

Question - are you using a std::map<string , ALLEGRO_BITMAP*(*)()> to return the function pointer?

Er.. no.

For some reason I thought maps were going to be hard to grasp and I thought I probably aught to wait a while until I've learnt a heap of other stuff first.

..but obviously you think I should be able to do it now and I think I get the gist of what your code does. Thanks for that... I'll have a go.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

If you get stuck, here's a good guide to the STL map class.

Use is fairly simple :

#SelectExpand
1// declare a map 2map<KEY_TYPE , VALUE_TYPE , optional_key_comparison_functor> mapname; 3 4// Add entry to the map 5mapname[KEY] = VALUE; 6 7// Get entry from the map 8VALUE = mapname[KEY]; 9 10// Modify entry in the map 11mapname[KEY] *= 2; 12 13// Iterate over all the values of the map : 14typedef map<KEY_TYPE , VALUE_TYPE> MY_MAP_TYPE;// to simplify typing 15 16for (MY_MAP_TYPE::iterator it = mapname.begin() ; it != mapname.end() ; ++it) { 17 KEY_TYPE key = it->first; 18 VALUE_TYPE value = it->second; 19 cout << "Key '" << key << "' , value = " << value << endl; 20}

The optional key comparison function is only needed if the key_type specified does not have key_type::operator<(const key_type& k) implemented (or the global operator< implemented). Also, the page I linked to earlier has an example of a comparison object at the beginning of the page.

One thing to be aware of is if you access the map using a key that isn't in the map, you will get an object of type VALUE_TYPE constructed using the default constructor. That's why you use the map member function find :

map<KEY_TYPE , VALUE_TYPE>::iterator it = mapname.find(key_type);
if (it == mapname.end()) {/* Not found */}
else {
   /// use the iterator it
}

Other useful functions are clear() and erase(iterator).

Go to: