Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Trouble not using global variables/functions

Credits go to Edgar Reynaldo, jmasterx, and Oscar Giner for helping out!
This thread is locked; no one can reply to it. rss feed Print
Trouble not using global variables/functions
Felix-The-Ghost
Member #9,729
April 2008
avatar

Ugh. I'm trying to rewrite my program to use classes/structs instead of globals.
Consider this thread the prequel.
I can't get this to compile:

main.cpp

...
#include "gamedata.h"
...
gamedata game;
...
set_close_button_callback(game.quit_game);
...

gamedata.h

#ifndef GAMEDATA
#define GAMEDATA


struct gamedata
{
    bool quit;

    void quit_game();
    void check_for_quit();
};

#endif

gamedata.cpp

void gamedata::gamedata()
{
    quit = false;
}

void gamedata::quit_game()
{
    quit = true;
}

void gamedata::check_for_quit()
{
//I don't even know what I'd do here
}

In main I get error: argument of type `void (gamedata::)()' does not match `void (*)()'

I really want to be able to write my program the right way :(

==========================
<--- The ghost with the most!
---------------------------
[Website] [Youtube]

jmasterx
Member #11,410
October 2009

You cannot set a callback to class functions, instead, you need to make polymorphic listeners or use a message system.

//your problem is:
set_close_button_callback(game.quit_game);

The basic idea is game.quit_game() actually points to a function that takes in an invisible pointer to your class instance (this) and so C++ won't know to use your 'game' instance because of how the language works. To do what you want, Google 'signal slot pattern' . std::function from c++0x can bind the this pointer so that could do it too.

A quick fix is to make quit_game() a static function. The disadvantage is that the function will be like a C one so it won't have access to your class's instance variables.

You would also access the static function like a scope:

set_close_button_callback(game::quit_game);

If you are just starting to learn Allegro, move to Allegro 5. It is better, and it supports proper events which will allow you to make your game object oriented more easily than Allegro 4.

Felix-The-Ghost
Member #9,729
April 2008
avatar

Last five times I checked, I have maybe the one modern-ish enough computer* that should but can't run Allegro 5 programs. I've been using Allegro 4 for my projects for 2-3 years. I'm just not too good at technical parts. Like horrible. But I got logic itself down enough to think it in my head.

I could use a global (is that what you mean by static) function, but that would require a global variable to check at the end of each loop. That's what I used to do, check if quit is true, then return from main.

Is there a small A5 program I can test on this computer? Compiled since the official release of A5?

*Its like a 2003 Dell running Win XP. Integrated graphics card. I don't know whether or not I feel like using A5 will shun users of older computers, but right now I'm starting to not care. It has been almost eight years :x

The project I'm rewriting was originally all in one source file, a little over 700 lines of code. A good part of it is comments and whitespace, but still more than I should be using one source for.

==========================
<--- The ghost with the most!
---------------------------
[Website] [Youtube]

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

There's no reason not to use a global variable here. Don't be paranoid about globals. Sometimes they're the right tool for the job.

bool quit = false;

void quit_game() {quit = true;}

// in main
set_close_button_callback(quit_game);

And yes, you could use a static quit variable and a static quit_game method. It would be effectively the same, except it would be affected by it's class access level.

Is there a small A5 program I can test on this computer? Compiled since the official release of A5?

Yes, download the examples for A5 from the allegro files page.

Oscar Giner
Member #2,207
April 2002
avatar

You can't avoid having a global here, since there's no version of set_close_button_callback that takes a callback with an extra parameter, like install_param_int does (in this case you could avoid the global, using a static member function and passing the "this" pointer manually).

Felix-The-Ghost
Member #9,729
April 2008
avatar

I'll use a global; in what situations is a global okay to use?

Also, just tried out some Allegro 5 examples and the demos. It's really cool (works) but before some games hadn't worked with me...

Non of the audio examples work with me nor the "acodec" examples.
OpenGL of course doesn't work with me since I think I need a good video card for that.

In some of the examples I can choose from a memory or video bitmap. Memory is really slow while video is fast. Is this to demonstrate a point? Allegro 4 used memory blending right?

Some other examples run a bit in their log windows but close quickly (I can't tell what some of them do just by trying the executable out :P)

The code for A5 is a lot different though :(
Where do I start? the manual? Or the wiki? Is there a guide for people that have been using A4 and want to transfer smoothly?

==========================
<--- The ghost with the most!
---------------------------
[Website] [Youtube]

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

In my opinion, globals are okay whenever you need a single shared instance of an object.

Non of the audio examples work with me nor the "acodec" examples.

They probably take an audio file name as an argument.

Try running the examples from the command line. Then they should tell you if they need command line parameters.

The manual and the wiki are the best places to learn Allegro 5. Ask questions here if you get stuck.

Matthew Leverton
Supreme Loser
January 1999
avatar

Removing globals does not guarantee a good design. If you put all of your globals into a struct and expose that struct, then you've accomplished nothing. The most important thing is to try to keep implementation details as private as possible.

If your computer is old, then I'd not bother with A5 until you at least upgrade the video card (if it's a desktop machine...).

Felix-The-Ghost
Member #9,729
April 2008
avatar

Most of the examples worked with my computer.
It's about 2003, running Win XP. I'm still interested in A5, should I use it?

Edit: I'm having trouble with external classes. Keeps saying I never defined it. In this case, it says player is never defined.

I'm trying to change the instance of the class snake, player's direction via a global function.

main.cpp

#SelectExpand
1#include <allegro.h> 2#include <vector> 3 4#include "gamedata.h" 5#include "snake.h" 6#include "segment.h" 7 8using namespace std; 9 10... 11 12/** GLOBAL VARIABLES **/ 13 14bool quit = false; 15 16/** GLOBAL FUNCTION DECLARATIONS **/ 17 18void quit_program(); 19void check_keys(); 20 21... 22
23snake player(game.buffer->w/2, game.buffer->h/2);
24 25... 26 27int main(void) 28{ 29 30... 31 32/** MAIN LOOP **/ 33 34while(!quit) 35{
36check_keys();
37 38game.draw(&player); 39} 40 41return 0; 42 43} END_OF_MAIN()

snake.h

#SelectExpand
1#ifndef SNAKE 2#define SNAKE 3 4#include "segment.h" 5 6#include <vector> 7using namespace std; 8 9class snake 10{ 11 public: 12 int head_x; 13 int head_y; 14 int head_dir; 15 16 vector <segment> body; 17 18 snake(int x, int y); 19}; 20 21#endif

snake.cpp

#include "snake.h"

snake::snake(int x, int y)
{
    head_x = x;
    head_y = y;
    head_dir = -1;
}

global_functions.cpp

#SelectExpand
1#include <allegro.h> 2#include "snake.h" 3
4extern snake player;
5 6extern bool quit; 7 8void quit_program() 9{ 10 quit = true; 11} 12 13void check_keys() 14{ 15 if (key[KEY_ESC]) 16 quit = true; 17 18 if (key[KEY_LEFT] && player.head_dir != 2) 19 {player.head_dir = 0; return;} 20 21 if (key[KEY_UP] && player.head_dir != 3) 22 {player.head_dir = 1; return;} 23 24 if (key[KEY_RIGHT] && player.head_dir != 0) 25 {player.head_dir = 2; return;} 26 27 if (key[KEY_DOWN] && player.head_dir != 1) 28 {player.head_dir = 3; return;} 29}

The extern worked on the global quit variable, but even in another incident I could not make the snake class external. I bypassed it earlier by passing the address of player, but I'd rather not have any function parameters for this (Or really the other function where I was drawing it)

I could have the snake class have its own code for checking keys, and in the check_keys function call that, but then each instance of the class would have the same controls (should I desire more instances). Is there a better (correct) way to do this?

==========================
<--- The ghost with the most!
---------------------------
[Website] [Youtube]

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

'extern' declarations go in headers, never in source files. All they do is say that 'this variable is available to you'. They still have to be defined somewhere else though.

I could have the snake class have its own code for checking keys, and in the check_keys function call that, but then each instance of the class would have the same controls (should I desire more instances). Is there a better (correct) way to do this?

Add 4 int members to your snake class that hold the value of the keys you want to check and then check if (key[MOVE_LEFT]) {...}. Look up what an initialization list is, as you don't use one. Give them default values in the initialization list.

gnolam
Member #2,030
March 2002
avatar

And never use namespaces in headers.

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

Felix-The-Ghost
Member #9,729
April 2008
avatar

gnolam said:

And never use namespaces in headers.

Noted, but is it unnecessary or destructive? Or both? I'll not do it, but I don't know why other than you said not to right now.

'extern' declarations go in headers, never in source files. All they do is say that 'this variable is available to you'. They still have to be defined somewhere else though.

Oh okay. I thought it'd function the same in the source file since it worked for the external Boolean variable quit. I'll try it in a header. I guess I'll need to make a globals declaration header. I'm hoping the creation of player in the main.cpp counts as a definition.

Quote:

Add 4 int members to your snake class that hold the value of the keys you want to check and then check if (key[MOVE_LEFT]) {...}. Look up what an initialization list is, as you don't use one.

Okay, I'm trying to look up "initialization lists", though I'm not sure what my goal is. So far it looks like just a constructor, but I'll keep reading into it I guess.

Quote:

Give them default values in the initialization list.

I'm not sure if this is supposed to be plainer to me, but I assume I'll know what you mean when I read more on these lists. Right now it looks ambiguous.

I've never succeeded in storing the keys flags in variables. I've asked for help in the past but I guess my wording was inaccurate cause I never got a satisfactory answer. I mean I don't know know how to store what keys is needed as a variable (I'm assuming you mean so I can initialize it with a constructor taking those keys as parameters, but I could be inferring wrongly)

==========================
<--- The ghost with the most!
---------------------------
[Website] [Youtube]

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

If you 'use' a namespace in a header, then every file that includes that header is automatically using that namespace as well, and it can lead to naming conflicts that can be avoided by not doing it.

Initialization lists are just that - write out your constructor prototype, then follow it by a semicolon, and then a comma separated list of constructor calls for each member of your class :

class Test {
   int i;
   char c;
   float f;
   
public :
   Test() :
      i(0),
      c('X'),
      f(3.14f)
   {
      // ... constructor body as normal
   }
};

I've never succeeded in storing the keys flags in variables. I've asked for help in the past but I guess my wording was inaccurate cause I never got a satisfactory answer. I mean I don't know know how to store what keys is needed as a variable (I'm assuming you mean so I can initialize it with a constructor taking those keys as parameters, but I could be inferring wrongly)

#SelectExpand
1int my_special_key = KEY_ENTER; 2 3// ... 4if (key[my_special_key]) {/*...*/} 5 6bool my_special_key_pressed = key[my_special_key]; 7if (my_special_key_pressed) {/*...*/} 8 9class Test { 10 int key1; 11 int key2; 12 13public : 14 Test() : key1(KEY_1) , key2(KEY_2) {} 15 Test(int key_one , int key_two) : 16 key1(key_one), 17 key2(key_two) 18 {} 19};

Felix-The-Ghost
Member #9,729
April 2008
avatar

int my_special_key = KEY_ENTER;

// ...
if (key[my_special_key]) {/*...*/}

Thanks, I haven't tested that, but I assume that works. I guess I didn't know they were integers. Seriously, thanks. I didn't know how to let my user configure keys. Does this work for shift/ctrl/alt flag, too?

Quote:

Initialization lists are just that - write out your constructor prototype, then follow it by a semicolon, and then a comma separated list of constructor calls for each member of your class :

Hmm. I didn't know you could do that in constructors. I guess you'd have to use constants, right? I mean to take parameters I'd need a constructor with parameters, yes (like parameters for keys to use, for example) I could always assign them later.
Oh I see you just have an overloaded constructor.

==========================
<--- The ghost with the most!
---------------------------
[Website] [Youtube]

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

You don't need to use constants in the constructor calls of the initialization lists :

class Test {
   int key1;
   int key2;

public :
   Test() : key1(KEY_1) , key2(KEY_2) {}
   Test(int key_one , int key_two) :
      key1(key_one),
      key2(key_two)
   {}
};

See how key1 is constructed using the value of the parameter key_one?

Any valid symbol or built in data type will do (as long as there is a constructor that takes that kind of object).

Felix-The-Ghost
Member #9,729
April 2008
avatar

Yeah I typed that before I saw the overloaded constructor :P

I just saw this Test() : key1(KEY_1) , key2(KEY_2) {}

Hey, do these count as the function declarations and definitions? Since the only code is there?

Edit:
I hit a problem when I made a header for my global variables.
In the global variables header, it says snake does not name a type.
I assume this is what's causing the gamedata.h to say that the instance of snake, player has not been declared.

My gamedata struct works, but the snake class isn't. Is there some different syntax to this or did I do something stupid?

gamedata.h

#SelectExpand
1#ifndef GAMEDATA 2#define GAMEDATA 3 4#include <allegro.h> 5 6#include "snake.h" 7 8struct gamedata 9{ 10 bool quit; 11 12 BITMAP* logo; 13 BITMAP* buffer; 14 BITMAP* bigbuffer; 15 16 gamedata(); 17 void init(); 18
19 void draw(snake* s);
20}; 21 22#endif

global_variables.h

#ifndef GLOBAL_VARIABLES
#define GLOBAL_VARIABLES

#include "snake.h"
#include "gamedata.h"

bool quit;
gamedata game;
snake player;
#endif

snake.h

#SelectExpand
1#ifndef SNAKE 2#define SNAKE 3 4#include "global_variables.h" 5#include "segment.h" 6#include "gamedata.h" 7 8#include <vector> 9 10class snake 11{ 12 public: 13 int head_x; 14 int head_y; 15 int head_dir; 16 17 std::vector <segment> body; 18 19 snake(): 20 head_x(game.buffer->w/2), 21 head_y(game.buffer->h/2), 22 head_dir(-1) 23 {} 24}; 25 26#endif

==========================
<--- The ghost with the most!
---------------------------
[Website] [Youtube]

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

First, you have a circular include cycle - global_variables.h includes snake.h which includes global_variables.h and so on...

Fix it by not including global_variables.h in snake.h. If you need access to variables in global_variables.h in snake.h, then you need to remove all references to the snake header in the global variables header.

Second, never define objects in a header, only declare them.

Example :

global_variables.h

#include "snake.h"
#include "gamedata.h"

extern snake player;
extern gamedata game;

global_variables.cpp

#include "global_variables.h"

snake player;
gamedata game;

I don't see why you need so many globals though. Can't you just pass a snake& or gamedata& to your functions instead?

Also, you can eliminate your player object from the globals by making it a member of your gamedata class. You will only ever have one snake right? So just add it to your gamedata class.

Then all you need to make everything available is :

gamedata.h

class gamedata {/*...*/};

extern gamedata game;

gamedata.cpp

#include "gamedata.h"

gamedata game;

And then when you need access to your game, you just include the gamedata header.

Felix-The-Ghost
Member #9,729
April 2008
avatar

Ahh, somehow I forgot -- I had even done it before, declaring the struct and class instances inside of the header that defines them. I moved the game and player declarations to gamedata.h and snake.h.

Yeah, I already have a function that is passed the address of player because of the same problem (not knowing player was [supposed to be] declared) I thought it'd be interesting to see if the code could handle another snake (just for testing, to see how easy it'd be with "correct" code)

forgetting to put "extern" was stupid of me. I don't know how I missed that (although I didn't realize that would define them)

gamedata.h still isn't liking this line, though

#SelectExpand
1#ifndef GAMEDATA 2#define GAMEDATA 3 4#include <allegro.h> 5 6#include "snake.h" 7 8struct gamedata 9{ 10 bool quit; 11 12 BITMAP* logo; 13 BITMAP* buffer; 14 BITMAP* bigbuffer; 15 16 gamedata(); 17 void init(); 18
19 void draw(snake* s);
20}; 21 22extern gamedata game; 23 24#endif

It doesn't know snake is a type, still (I thought including the snake.h would fix that)

I only planned on one more global at most, but I probably will add the snake instance to gamedata. I had already pondered on it.

I'm not sure if I should just declare the bool quit in main.cpp or not (getting rid of the global_variables.h) since only main is using quit

I can tell circular includes is gonna be a problem for me. I thought the

#ifndef GLOBAL_VARIABLES
#define GLOBAL_VARIABLES
#endif

made it okay. Hmm. I was originally just including the headers in other headers using classes/structs from them (eg including snake.h in gamedata.h but not working as I planned)

I think I did everything you said... Here let me paste what I got:

global_variables.h (will probably get rid of this)

#ifndef GLOBAL_VARIABLES
#define GLOBAL_VARIABLES

#include "gamedata.h"

extern bool quit;

#endif

gamedata.h

#SelectExpand
1#ifndef GAMEDATA 2#define GAMEDATA 3 4#include <allegro.h> 5 6#include "snake.h" 7 8struct gamedata 9{ 10 bool quit; 11 12 BITMAP* logo; 13 BITMAP* buffer; 14 BITMAP* bigbuffer; 15 16 gamedata(); 17 void init(); 18 19 void draw(snake* s); 20}; 21 22extern gamedata game; 23 24#endif

snake.h

#SelectExpand
1#ifndef SNAKE 2#define SNAKE 3 4#include "segment.h" 5#include "gamedata.h" 6 7#include <vector> 8 9class snake 10{ 11 public: 12 int head_x; 13 int head_y; 14 int head_dir; 15 16 std::vector <segment> body; 17 18 snake(): 19 head_x(game.buffer->w/2), 20 head_y(game.buffer->h/2), 21 head_dir(-1) 22 {} 23}; 24 25extern snake player; 26 27#endif

I appreciate your patience in helping me with this. This is really not coming easy to me, and I struggled with learning it in the past and gave up and coded everything in one file :(

==========================
<--- The ghost with the most!
---------------------------
[Website] [Youtube]

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

It doesn't know snake is a type, still (I thought including the snake.h would fix that)

There must be something wrong with your snake.h header then, because as long as the class is declared properly it should work. Post the latest snake.h.

Felix-The-Ghost said:

I can tell circular includes is gonna be a problem for me. I thought the

#ifndef GLOBAL_VARIABLES
#define GLOBAL_VARIABLES
#endif

made it okay. Hmm.

The header guards prevent the same header from being included twice in the same file, but circular inclusion is still wrong and can lead to other problems. If a function needs info from more than one header, then it should be a separate header as well.

You've got another circular include going on - gamedata.h includes snake.h which includes gamedata.h. Both classes shouldn't need to know about each other.

Fix it by adding class snake; in gamedata.h before you declare class gamedata. That is known as a forward declaration, and allows you to use pointers and references to whatever you forward declare that way.

However, you are doing something a little dangerous - you are using a global object (game) inside your snake constructor. If snake is defined before game, then you will be referencing an object that hasn't been constructed yet. :o

You should never rely on global constructor order, since it is undefined across compilation units. I'm pretty sure in a single file it goes in the order they are defined, but you still shouldn't count on it.

To fix it, just use a setter method in your snake class where you initialize its position.

Felix-The-Ghost
Member #9,729
April 2008
avatar

Sweet. Something clicked for me -- I had been including whole headers (in other headers) when a certain struct/class wasn't recognized. So I do forward declarations instead, and in source files (cpp) there, I include the headers. I might be wrong with this, but I compiled with no warnings (I had to modify pretty much every file, and I eliminated global_variables.h)

main.cpp

#SelectExpand
1#include <allegro.h> 2#include <vector> 3 4#include "gamedata.h" 5#include "snake.h" 6#include "segment.h" 7 8using namespace std; 9 10/** GLOBAL VARIABLES **/ 11 12bool quit = false; 13gamedata game; 14snake player; 15 16... 17 18game.init(); 19 20...

gamedata.h

#SelectExpand
1#ifndef GAMEDATA 2#define GAMEDATA 3 4struct BITMAP; 5 6class snake; 7 8struct gamedata 9{ 10 BITMAP* logo; 11 BITMAP* buffer; 12 BITMAP* bigbuffer; 13 14 void init(); 15 16 void draw(snake* s); 17}; 18 19extern gamedata game; 20 21#endif

gamedata.cpp

#include <allegro.h>
#include "gamedata.h"
#include "snake.h"

...
}

snake.h

#SelectExpand
1#ifndef SNAKE 2#define SNAKE 3 4#include "segment.h" 5#include "gamedata.h" 6 7#include <vector> 8 9class snake 10{ 11 public: 12 int head_x; 13 int head_y; 14 int head_dir; 15 16 std::vector <segment> body; 17 18 snake(): 19 head_dir(-1) 20 {} 21 22 void position(int x, int y); 23}; 24 25extern snake player; 26 27#endif

snake.cpp

#include "snake.h"
void snake::position(int x, int y)
{
    head_x = x;
    head_y = y;
}

global_functions.cpp

#SelectExpand
1#include <allegro.h> 2 3#include "snake.h" 4 5extern snake player; 6extern bool quit; 7 8void quit_program() 9{ 10 quit = true; 11} 12 13void check_keys() 14{ 15 if (key[KEY_ESC]) 16 quit = true; 17 18 if (key[KEY_LEFT] && player.head_dir != 2) 19 {player.head_dir = 0; return;} 20 21 if (key[KEY_UP] && player.head_dir != 3) 22 {player.head_dir = 1; return;} 23 24 if (key[KEY_RIGHT] && player.head_dir != 0) 25 {player.head_dir = 2; return;} 26 27 if (key[KEY_DOWN] && player.head_dir != 1) 28 {player.head_dir = 3; return;} 29}

It compiles fine, but are there some bad include practices in there I should know about? I really appreciate your help so far, I got a lot of this down (finally), but I'm not sure this is 100% "correct".

I probably don't need to include <vector> in snake.h, do I? I should use a forward declaration, but what is a vector? A struct/class? Hmm. Googling. the std:: thing takes care of it I think. I know that is supposed to mean standard namespace or something, but I don't really know why that works.

==========================
<--- The ghost with the most!
---------------------------
[Website] [Youtube]

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

global_functions.cpp

#include <allegro.h>

#include "snake.h"

extern snake player;
extern bool quit;

Don't use extern in source files - it's akin to cheating, and besides, including snake.h took care of that for you already.

snake.h no longer needs to include gamedata.h because you aren't using 'game' references in it anymore.

I probably don't need to include <vector> in snake.h, do I? I should use a forward declaration, but what is a vector? A struct/class? Hmm. Googling. the std:: thing takes care of it I think. I know that is supposed to mean standard namespace or something, but I don't really know why that works.

snake.h needs to know about the vector class template, so you do need to include <vector>. Forward declarations don't work when you want to define objects of that class or use them by value.

About namespaces :

header.h

namespace MYLIB {
   class MYCLASS {/*...*/};
}

main.cpp

#include "header.h"

using namespace MYLIB;// this brings every symbol declared in MYLIB into global scope

using MYLIB::MYCLASS;// this brings only the MYCLASS symbol into scope

int main(int argc , char** argv) {

   MYLIB::MYCLASS myclass;// fully qualified, helps avoid name collisions
   MYCLASS myclass;// using the short name to refer to it

   return 0;
}

Felix-The-Ghost
Member #9,729
April 2008
avatar

Don't use extern in source files - it's akin to cheating, and besides, including snake.h took care of that for you already.

snake.h no longer needs to include gamedata.h because you aren't using 'game' references in it anymore.

Oops, missed those. I must've hurried through it.

I'll have to read up on namespaces, I guess, cause I still don't really get them (as far as usefulness of custom namespaces)

edit: I fixed those includes and globals (I brought back global_variables.h for quit for global_functions.cpp

I was removing including custom headers in other headers, but I got a problem when I don't include segment.h in snake.h, even with a forward declaration of segment

snake.h

#SelectExpand
1#ifndef SNAKE 2#define SNAKE 3 4#include <vector> 5
6class segment;
7 8class snake 9{ 10 public: 11 int head_x; 12 int head_y; 13 int head_dir; 14
15 std::vector <segment> body;
16 17 snake(): 18 head_dir(-1) 19 {} 20 21 void position(int x, int y); 22}; 23 24extern snake player; 25 26#endif

segment.h

#ifndef SEGMENT
#define SEGMENT

class segment
{
    public:
    int x;
    int y;
};

#endif

It says error: invalid use of undefined type `struct segment'
Not sure why it says struct and not class...
Hmm? Segmentation fault? :B

Actually, currently until I make a segment.cpp, nothing includes segment.h -- is it still declared, then?

==========================
<--- The ghost with the most!
---------------------------
[Website] [Youtube]

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

I was removing including custom headers in other headers, but I got a problem when I don't include segment.h in snake.h, even with a forward declaration of segment

Edgar said:

Forward declarations don't work when you want to define objects of that class or use them by value.

You're using a vector of segment objects, and so it needs to know what they are, not just that they exist, so forward declarations won't work in this case. Forward declarations only work when you're using pointers or references, and you still need their full declaration when you go to use them (in a source file).

Felix-The-Ghost said:

It says error: invalid use of undefined type `struct segment'
Not sure why it says struct and not class...

To save having two error messages instead of one? Don't know, but like I said, it needs to know the full declaration of the segment class.

Felix-The-Ghost said:

Actually, currently until I make a segment.cpp, nothing includes segment.h -- is it still declared, then?

If you never include it, it was never declared.

Felix-The-Ghost said:

I was removing including custom headers in other headers,

There's nothing wrong with including headers in headers, if they need to know about what is declared in them.

Felix-The-Ghost said:

I'll have to read up on namespaces, I guess, cause I still don't really get them (as far as usefulness of custom namespaces)

Namespaces help avoid naming collisions when using multiple libraries. Imagine A and D are from two different libraries - if class C were declared in both libraries without being inside a namespace, then you would have problems.

namespace A {
   class C {int y;};
}
namespace D {
   class C {int x;};
}

int main(int argc , char** argv) {
   A::C ac;
   D::C dc;
   return 0;
}

Felix-The-Ghost
Member #9,729
April 2008
avatar

Oh, I get it now. Thanks, man!

==========================
<--- The ghost with the most!
---------------------------
[Website] [Youtube]

Go to: