struct, class or global variables?

Hi,
This is more a question of how to approach a problem rather than a difficulty with specific code. I'm pretty new to c++ and am trying to test what I've learned by building a simple console game.

Anyway, I have some variables that I will need to access from many places in the code, but I only need one of each. This sounds like a job for global variables but is it worth building a struct to give each a definite address? Also as structs are basically limited classes, is it worth using a class instead?

Sorry if this is a little vague. I get the feeling there is no right answer, but would like to hear some opinions and reasons for them.
Global:
1
2
3
4
5
6
7
8
9
10
int a = 1;
double b = 0.5;

double foo() {
  return a * b;
}

int main() {
  double d = foo();
}


Struct:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct Bar {
  int a;
  double b;
  Bar( int, double );
};

double foo( const Bar & c ) {
  return c.a * c.b;
}

int main() {
  Bar p( 42, 0.3 );
  double d = foo( p );
}

With struct you can somewhat limit on who can access the parameters, but you have to pass the struct into the functions. You have better control over the lifetime of the data too (initialization and destruction of globals is beyond main). A class is a struct, but with different default access rule.
I would recommend using global variables, if you're just representing simple things such as levels or money. You would want to keep the code clean and not go and create structs and classes for things that only hold one value. If your game is more advanced with enemies that have their own stats, etc, then it would be better to use structs to organize the variables. It all depends on what the variables are used for.
Globals are almost always the wrong solution.

If you write your code to use global variables, then your code only works with global variables. Whereas if you write your code to use parameters that are passed to it, it can work on any variable.

So not only does avoiding globals keep your code more organized, but it also makes your code more flexible and adaptable.

So yeah... AVOID GLOBALS. There are very few situations where global variables are appropriate, and until you understand enough about variable scope to recognize what those situations are... the general guideline is to just not use them at all.



Structs are not really "limited classes". Classes are conceptually 'encapsulated objects', meaning they are self contained and modify their data on their own, while providing functions which perform common tasks to outside code.

Whereas structs are just a collection of variables that are generally modified by outside code.

Until you 'get' encapsulation, you can just stick with structs. But encapsulation and OOP are definitely concepts you'll want to try and learn. Although it's a difficult concept to grasp at first. Plus, academia does a pretty lousy job of teaching it.



That's about as much advice as I can give you without more details of your specific problem.
Last edited on
You're right, there's no one right answer.

While it is certainly best to minimize your use of globals, placing them in a global struct doesn't accomplish much. It can make sense if they're related in some way, such as a table.

A global struct doesn't hide their visibility and you can still end up modifying members of a global struct from all over your code, which can be a maintenance and debugging nightmare.

What I tend to do is create a top level class for my program. All main does is to instantiate that class and then call that classes' initialize and execute functions. What this accomplishes is that when main exits, my class destructor gets called giving it a chance to clean up. What would become global variables or local variables within main become appropriately scoped variables within that class. This isn't a panacea though. You can still end up with lots of variables in that class accessed from all over the place. There is no substitute for well thought out design of your classes.

is it worth building a struct to give each a definite address

Every global variable will have a definite address regardless of whether it's in a struct or not.


Thank you for all your responses.

Disch
That's about as much advice as I can give you without more details of your specific problem.


That's the level of advice I was hoping for. I like to try and 'get' (as you put it) the concepts behind what I'm doing and feel the best way to do that is get an approach to a class of problem, rather than a specific solution to a specific problem.

Abstraction Anon
Every global variable will have a definite address regardless of whether it's in a struct or not.


Yes, one of the things of being new to something is that sometimes you miss where what you say could introduce ambiguity. When I say definite address, I mean from a debugging perspective, looking for a (for example) 'struct.score' may be easier than spotting a 'score' on it's own.

Keskiverto
Thanks for the example. I was a little surprised to see what looks like constructor in your struct definition. I've not seen this in my reading so far. Am I right in thinking this is what it is
Bar( int, double );
and if so is the benefit simply the convenience of initializing both elements at the same time or is this approach something I'd need if I want to pass my struct to a function?

Certainly it's tempting to use globals just to make life easier, but the consensus seems to be to avoid them.

I'm now going to find some reading on encapsulation. Please keep the replies coming if you have anything to add.
I did leave out the implementation of the constructor:
Bar::Bar( int A, double B ) : a( A ), b( B ) {}
Yes, a struct can have a constructor just like a class.

Third variant, implied by others:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Bar {
  int a;
  double b;
public:
  Bar( int, double );
  double foo() const;
};

Bar::Bar( int A, double B ) : a( A ), b( B ) {}

double Bar::foo() const {
  return this->a * this->b;
}

int main() {
  Bar p( 42, 0.3 );
  double d = p.foo();
}

Now both the data (the parameters) and procedures that operate on that data are presented together as a "Bar object".
Topic archived. No new replies allowed.