4.6 The code interface

There's two ways of thinking of your body of code: the semantics and the syntax. The semantics of your code has to do with what it means, and the syntax has to do with what the text in your files actually looks like.

At the semantic level, your code is used to prototype and implement classes and to weave some class objects together into your program's run-cycle. That's what we've been talking about so far in this chapter.

In this section we'll say a little about your code syntax, and how you can make the syntax more 'object-oriented' ? in the sense of being more like a black box with an interface of clearly accessible switches and settings.

Of course code is really more of a white box, since you can open up the files and read every bit of them. The point is that if you organize your code in a nice way, you can put something like an interface into it. Here we're not using 'code interface' in the sense of the class prototypes found in the header files ? those are the class interfaces. By code interface we mean a collection of tricks and idioms that experienced programmers use to make their implementation files more tweakable.

C++ language features useful for creating a good code interface include the following.

#define
switches for #ifdef
code blocks.

typedef
statements for renaming types.

static variables.

static methods.

Detailed information about #define
and #ifdef
can be found in the Preprocessor Directives section of the Part II Chapter 22: Topics in C++. Quite briefly, if you have two possible versions of some code, or a piece of code that you only want to turn on sometimes (for instance when debugging), it's a good idea to use a #define
and an #ifdef. So you might have something like this example taken from critter.cpp.

When you have #define-controlled switches like this, be sure to put the #define line up at the top of the *.cpp (or *.h) file where it's used, and follow it by a long comment explaining the consequences of turning this switch off or on by, respectively, commenting it out or leaving it in.

Another type of code interface switch uses typedef. In the Pop Framework we use a lot of floating point real numbers. So as to avoid having to permanently commit to whether we want to use the faster float
or the more accurate double, we have a file realnumber.h
that includes these two lines.

//typedef double Real;
typedef float Real;

At present we're going for more speed and less accuracy, but if it ever seemed better to have more accuracy at the expense of speed, we would only need to edit those two lines. And everywhere in our files where we need a real number, we always use the defined type Real, rather than float
or double. For this to work, of course, we have to have an #include realnumber.h in all of these files.

A simpler kind of code interface setting is a parameter whose value affects the way the program works. Always try and avoid putting raw 'magic numbers' in our code. Instead of a raw number you should either use a #define
or, better, a static variable.

Using static variables is an example of a good OO practice that is more common in Java programming. In Java it's very easy to declare and initialize a static variable, you simply place it right into your class definition. In C++ it's a bit harder. You declare the static variable inside your class header, but you have to actually set the variable's value down inside one of your *.cpp
files. As we show in Figure 4.14, a class will have multiple object instances, but all of these are thought of as showing the same static variables, and they all agree on the values of these variables.

Figure 4.14. Objects share the static members of the class

Sometimes we make our static variables public; in this case they're the closest thing to a global variable that OOP allows. A static variable that you set once and for all is typed as a const. In Windows programming, a color is coded up as a 32-bit integer with the three right-most byte fields representing the red, green, and blue intensities, which can range from 0 to 255. An RGB
macro assembles three intensities into a color-coding integer. To avoid having to remember all this, we can make public static const int
variables in, say, a cColorStyle
class. The colorstyle.h
header would have code like this.

And the colorstyle.cpp
would instantiate the static variable, giving it a place to 'live' by using a line like this.

const int cColorStyle::CN_RED = RGB(255, 0, 0);

The line does not appear inside any method, it's simply in the file as is. Note that when you instantiate a static you also are allowed to initialize it. Unlike Java, C++ won't let you initialize a static inside the class prototype in the header file. (Well, actually ANSI C++ will let you do this if it's a const
static, but Microsoft C++ won't in any case.)

If a static variable is public, we can access it in any file of our code, assuming that file has included the header where the static's owner class is protoyped. A typical use of a static looks like this.

ppolygon->setFillColor(cColorStyle::CN_RED);

As a matter of good programming, we always prefix a reference to a static by its owner class name and the scope resolution operator '::'. You don't actually need this prefix if you are using the static within a method of the static's owner class, but it makes the code more uniform and easier to follow. It's also good practice to consistently use a different name style for statics; in the Pop Framework we always capitalize them.

We typically instantiate our statics in the *.cpp that matches the *.h file where they're declared. The statics specific to cGameSpacewar
are initialized in gamespacewar.cpp, the statics specific to cGamePicknpop
are initialized in gamepicknpop.cpp
and so on.

The 'code interface' aspect of statics involves using them for parameters that we may wish to change during successive builds of the program ? unlike a fixed constant like CN_RED. When you write a game, there are a lot of values that you may want to change repeatedly. If these are statics initialized (and well-commented) at the head of the *.cpp file, it's easy to keep adjusting them until you see the performance you like.

A few more facts about static variables. You can, if you like, instantiate a static in any *.cpp
file you like. Generally it's easier to find them if they live in the file that goes with the header that declares them. But sometimes you may want to group a bunch of statics together, particularly if their initialization values depend upon each other. In the Pop Framework, for instance, we instantiate the 'mutation flag' statics all inside a file we created called static.cpp.
The reason is so that we can make sure that these single-bit flag variables don't have conflicting values.

If a static has the const
modifier, that means you aren't allowed to change its value anywhere in the code, other than in the line where you initialize it. Other statics can in fact be changed. One use of a non-const
static might be a variable to keep track of whether any instance of a given class has been initialized yet. Thus we declare a static BOOL FIRSTTIME variable in graphicsopengl.h, instantiate it in the *.cpp
as BOOL cGraphicsOpenGL::FIRSTTIME = TRUE, and have some code that, if FIRSTIME is TRUE, sends some informational output and sets FIRSTTIME to FALSE. Or you might use a static intINSTANCECOUNT to track how many objects of a given type have been created, initializing INSTANCECOUNT to 0 and letting the class constructor and destructor respectively increment and decrement INSTANCECOUNT.

There are a number of reasons why it's better to use static variables rather than #define
parameters.

Type checking is performed on static variables, but not on #define
parameters.

Since the initialization of the statics is inside a *.cpp
rather than inside a *.h, when you change the value of a static parameter, you don't need to recompile as much of your code.

If you always put the class name and scope resolution operator in front of your static names, this adds a level of self-documentation to your code that #define
names don't give you.

Static variable names are less likely to cause namespace conflicts than #define
names. That is, if you #define
a name like CRITTERSPEED in two different files, your compiler won't like this. But if you have a cGameRunner::CRITTERSPEED and a cGameWalker::CRITTERSPEED there's no conflict.

Using statics is a good habit to get into because it's useful for having OO-correct versions of things very much like global variables, such as the single static cRandomizer cRandomizer::RANDOMIZER object defined in our randomizer.h
and randomizer.cpp
files. This way, whenever we need a randomizer anywhere in our program, we just use cRandomizer::RANDOMIZER.

Since a static is a variable, you can change it inside your code. Thus, for instance, many of our cGame
child classes change the value of the static RealcCritter::MAXRADIUS as a way of altering the default maximum size of all the critters.

Java doesn't allow the #define
statement, so you might as well start learning to live without it.