In my limited experience, the larger the program, the more globals it tends to accumulate, and the harder it is to keep track of them, the more likely they'll be used by classes that shouldn't be using them, breaking that class's "self-contained" nature by making them rely on external variables, making the whole program more interdependent than it should be, making it harder to maintain and expand.
In small programs, this doesn't seem like a problem, but when I get into the habit of having globals just for the convenience of not doing it the more tedious but proper way, then if that small program ever grows large, or if you come to rely on that convenience and carry it over to larger projects, it might trouble you later.
A few key globals in a large project can be useful, but you have to keep your globals in check, because - due to laziness - mine tend to proliferate once I allow myself a few of them, and before I know it, three turns into twenty and then forty and more unless I get and keep them in check.
In a bid to fight them off, but still being lazy, the next poor step I usually accidentally take is by creating a class that pretends to not be global but really is a container for globals in disguise - like a singleton that holds the globals, or a class that holds a huge number of named "properties" (read: globals behind a fake mustache).
Non-private static members of classes are another way of pretending a global isn't a global and deceiving myself.
One of the hidden issues with globals is that globals across dynamic libraries can cause compiling problems depending on your compiler, and another problem is that globals (and static members) are initialized in an undefined order. The only guarantee you have is that they are constructed before main() enters, but if one is dependant on another, you don't have any guarantee which will be constructed first.
Though those issues can be worked around, doing so leaves me finding myself investing work into something that makes the code harder to maintain just to avoid writing proper code architecture in the first place (which I have difficulty designing properly, which is why I try to avoid it!).
Globals aren't evil, but they are super-easy to abuse.
I like a few constant values, enums, etc... as globals, but anything that could be named a 'system' is something that should be passed into a class's constructor or a function call by pointer. It means more coding work up-front, more fore-thought, more "ugh, why am I bothering to write these extra function arguments" moments, but a cleaner program architecture overall in the long-term.
...says the person who rewrites his programs several times because he didn't take the time to think it through and plan it properly.
Edited by Servant of the Lord, 03 October 2013 - 02:03 PM.