|
This thread is locked; no one can reply to it. |
1
2
|
[A5] Object Oriented Programming -Confusing. |
Matias Persson
Member #15,093
May 2013
|
It's okay I have modified the code you showed me, and I have put it all in classes. 1#pragma once
2#include "Includes.h"
3#include "Buttons.h"
4
5class Game
6{
7public:
8 Game(void);
9
10 bool initialize();
11 void load_resources();
12 void loop();
13 void destroy();
14 void shutdown();
15private:
16 Buttons buttons;
17 ALLEGRO_DISPLAY *display;
18 ALLEGRO_EVENT_QUEUE *event_queue;
19 ALLEGRO_TIMER *timer;
20 ALLEGRO_BITMAP *abg;
21 ALLEGRO_BITMAP *bg;
22 ALLEGRO_BITMAP *menub;
23 ALLEGRO_BITMAP *login;
24 ALLEGRO_BITMAP *menub2;
25 ALLEGRO_BITMAP *creation;
26 ALLEGRO_BITMAP *readfirst;
27 ALLEGRO_SAMPLE *lsm;
28
29 bool redraw;
30
31 //Clicks
32 bool loginclicked;
33 bool accountclicked;
34 bool okclicked;
35
36 //Hovers for menu screen
37 bool hovercreate;
38 bool hoverplay;
39 bool hovercredits;
40 bool hoverexit;
41 bool hoverconnect;
42 bool hovercancel;
43 //Hovers for account creation screen
44 bool hovercreate2;
45 bool hovercancel2;
46 bool hoverok;
47};
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
See all those instances of 'hover*'? You can replace them with a single instance member variable in your Button class called hover, and use one for clicked as well. Then when you want to see if a certain button has been clicked you check it's HasHover() or IsClicked() method. Edit My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Neil Roy
Member #2,229
April 2002
|
Matias Persson said: I thought it was bad to use global variables? :S I have no problem using them. In his example is a good example of global variables. This way he can call shutdown() from anywhere in his program and it will free up the allocated memory. It's the only reason I will use them, for this like this where you have a variable allocated like the display which you will need freed up later and possibly used from several locations. There are ways to avoid this, but I don't see how creating more confusing code JUST to avoid globals is a good thing, so you need to take what people say with a grain of salt. Quote:
My understanding of structs is not good.
Structs originated with C. They're basically like classes, only without functions. At least in C. C++ treats structs as classes with it's member's public by default. Here's a nice explanation of them on this website... --- |
Arthur Kalliokoski
Second in Command
February 2005
|
IIRC, the problems with global variables are: They have global names, so it can be hard to come up with meaningful names that don't clash. They aren't optimized as well by the compiler, since the compiler may decide to keep a local variable in a register only. They're not allocated on the stack, so even if a local variable isn't held entirely in a register it's pretty much guaranteed to be cached since the stack was accessed just for the function call. They all watch too much MSNBC... they get ideas. |
Chris Katko
Member #1,881
January 2002
|
Arthur Kalliokoski said: They aren't optimized as well by the compiler, since the compiler may decide to keep a local variable in a register only. If optimization is your problem, your actual problem is everything you've done in the entire project. (Read: Bad algorithms and bad design.) Since optimization generally gets you 20-30% speed up at best, whereas algorithm selection controls orders of a magnitude speed up and slow down of your program. So I would never really consider that an issue for using or not using globals. Globals are like GOTO statements. If you design everything properly, you probably (but not always!) won't need them. But they can be very handy if used sparingly for rapid development. But I'm just saying that for general readers--I know you know all this. -----sig: |
bamccaig
Member #7,536
July 2006
|
Using localized state far outweighs any perceived "benefits" of global state. This little snippet demonstrates that you can easily pass around an "application scope" chunk of memory to the places that need it (only) with little extra code. The main advantages are that you can easily see which state affects a particular function in the program (because we're smart people that refuse to reach into the global namespace), and you can easily make changes to it without affecting the rest of the program and without having to do extra work [carefully] to undo the tampering that you've done, without worrying that unrelated parts of the program could affect us. 1#include "magic.h"
2#include <memory.h>
3#include <stdio.h>
4#include <stdlib.h>
5
6typedef struct {
7 const char * filename;
8 int force;
9 int timeout;
10 int verbose;
11} APP_STATE;
12
13void contrived1(APP_STATE * const); 14void contrived2(const APP_STATE * const); 15
16void parse_args(
17 APP_STATE * const,
18 const int,
19 const char * const * const);
20
21const char * require_value(
22 const char,
23 const char * const *,
24 const char * const *);
25
26APP_STATE * state_alloc(void);
27
28APP_STATE * state_clone(const APP_STATE * const);
29
30APP_STATE * state_create(void);
31
32void state_destroy(APP_STATE **);
33
34void state_init(APP_STATE * const);
35
36int main(int argc, char * argv[])
37{
38 APP_STATE * _ = state_create();
39
40 parse_args(_, argc, (const char * const *)argv);
41
42 contrived1(_); 43
44 state_destroy(&_);
45
46 return 0;
47}
48
49void contrived1(APP_STATE * const _) 50{ 51 APP_STATE * _2 = state_clone(_); 52 53 // For this localized example we'll double the timeout.
54 _2->timeout *= 2; 55 56 contrived2(_2); 57 58 state_destroy(&_2); 59} 60 61void contrived2(const APP_STATE * const _) 62{ 63 magic_sort_file(_->filename, _->timeout, _->force, _->verbose); 64} 65
66void parse_args(
67 APP_STATE * const _,
68 const int argc,
69 const char * const * argv)
70{
71 int bypass = 0;
72 const char * const * end = argv + argc;
73
74 while(++argv < end)
75 {
76 const char * arg = *argv;
77
78 if(bypass || *arg != '-')
79 {
80 _->filename = arg;
81 }
82 else if(*++arg == '\0')
83 {
84 _->filename = "-";
85 }
86 else if(*arg == '-')
87 {
88 bypass = 1;
89 }
90 else
91 {
92 char opt = *arg;
93
94 switch(opt)
95 {
96 case 'f':
97 _->force = 1;
98 break;
99 case 't':
100 _->timeout = atoi(require_value(opt, ++argv, end));
101 break;
102 case 'v':
103 _->verbose = 1;
104 break;
105 }
106 }
107 }
108}
109
110const char * require_value(
111 const char opt,
112 const char * const * value,
113 const char * const * end)
114{
115 if(value == end)
116 {
117 fprintf(stderr, "Option -%c requires a value.\n", opt);
118
119 exit(1);
120 }
121
122 return *value;
123}
124
125APP_STATE * state_alloc(void)
126{
127 return (APP_STATE *)malloc(sizeof(APP_STATE));
128}
129
130APP_STATE * state_clone(const APP_STATE * const _)
131{
132 APP_STATE * _2 = state_alloc();
133
134 if(_2 != 0)
135 {
136 memcpy(_2, _, sizeof(APP_STATE));
137
138 _2->filename = strdup(_->filename);
139 }
140
141 return _2;
142}
143
144APP_STATE * state_create(void)
145{
146 APP_STATE * _ = state_alloc();
147
148 if(_ != 0)
149 {
150 state_init(_);
151 }
152
153 return _;
154}
155
156void state_destroy(APP_STATE ** __)
157{
158 free(*__);
159 *__ = 0;
160}
161
162void state_init(APP_STATE * const _)
163{
164 memset(_, 0, sizeof(APP_STATE));
165
166 _->timeout = 250;
167}
This also allows you to easily test the code. You can write little tests that set up an APP_STATE exactly how its needed and see how little chunks of your program respond to it without having to invoke a long chain of the main program. Your tests can even run within a single process without having to tear down and start back up because you've remained smart and kept state local guaranteeing (with the exception of memory access bugs) that one test will not tamper with another one. If you have never done it then give it a try. Honestly, it is so much nicer when the needs of a function are explicitly defined. You gain so much for so little. It will also make you a better programmer guaranteed because it will force you to think in situations where global state would let you be lazy. This will help you to discover mistakes in your design earlier and fix them before they become the cause of a week long debugging session and another week of application-wide refactoring. Just. Don't. Use. It. Append: I'd rather see goto than global state. I'm convinced the latter is a bigger evil than the former. -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
Arthur Kalliokoski
Second in Command
February 2005
|
Chris Katko said: If optimization is your problem, your actual problem is everything you've done in the entire project. (Read: Bad algorithms and bad design.) I didn't say optimization was a problem, I said you get more optimization "for free", i.e. no tricks or hard to read code, by using locals. OTOH, for a little toy program the globals would likely fit in the cache too. They all watch too much MSNBC... they get ideas. |
|
1
2
|