The C Preprocessor

The C preprocessor modifies a source code file before handing it over to the compiler. You're most likely used to using the preprocessor to include files directly into other files, or #define constants, but the preprocessor can also be used to create "inlined" code using macros expanded at compile time and to prevent code from being compiled twice. 

There are essentially three uses of the preprocessor--directives, constants, and macros. Directives are commands that tell the preprocessor to skip part of a file, include another file, or define a constant or macro. Directives always begin with a sharp sign (#) and for readability should be placed flush to the left of the page. All other uses of the preprocessor involve processing #define'd constants or macros. Typically, constants and macros are written in ALL CAPS to indicate they are special (as we will see).

Header Files

The #include directive tells the preprocessor to grab the text of a file and place it directly into the current file. Typically, such statements are placed at the top of a program--hence the name "header file" for files thus included.

Constants

If we write
#define [identifier name] [value]
whenever [identifier name] shows up in the file, it will be replaced by [value]. 

If you are defining a constant in terms of a mathematical expression, it is wise to surround the entire value in parentheses:
#define PI_PLUS_ONE (3.14 + 1)
By doing so, you avoid the possibility that an order of operations issue will destroy the meaning of your constant:
x = PI_PLUS_ONE * 5;
Without parentheses, the above would be converted to
x = 3.14 + 1 * 5;
which would result in 1 * 5 being evaluated before the addition, not after. Oops! 

It is also possible to write simply
#define [identifier name]
which defines [identifier name] without giving it a value. This can be useful in conjunction with another set of directives that allow conditional compilation.

Conditional Compilation

There are a whole set of options that can be used to determine whether the preprocessor will remove lines of code before handing the file to the compiler. They include #if, #elif, #else, #ifdef, and #ifndef. An #if or #if/#elif/#else block or a #ifdef or #ifndef block must be terminated with a closing #endif. 

The #if directive takes a numerical argument that evaluates to true if it's non-zero. If its argument is false, then code until the closing #else, #elif, of #endif will be excluded.

Commenting out Code

Conditional compilation is a particularly useful way to comment out a block of code that contains multi-line comments (which cannot be nested).
#if 0
/* comment ...
*/

// code

/* comment */
#endif

Avoiding Including Files Multiple Times (idempotency)

Another common problem is that a header file is required in multiple other header files that are later included into a source code file, with the result often being that variables, structs, classes or functions appear to be defined multiple times (once for each time the header file is included). This can result in a lot of compile-time headaches. Fortunately, the preprocessor provides an easy technique for ensuring that any given file is included once and only once. 

By using the #ifndef directive, you can include a block of text only if a particular expression is undefined; then, within the header file, you can define the expression. This ensures that the code in the #ifndef is included only the first time the file is loaded.
#ifndef _FILE_NAME_H_
#define _FILE_NAME_H_

/* code */

#endif // #ifndef _FILE_NAME_H_
Notice that it's not necessary to actually give a value to the expression _FILE_NAME_H_. It's sufficient to include the line "#define _FILE_NAME_H_" to make it "defined". (Note that there is an n in #ifndef--it stands for "if not defined"). 

A similar tactic can be used for defining specific constants, such as NULL:
#ifndef NULL
#define NULL (void *)0
#endif // #ifndef NULL
Notice that it's useful to comment which conditional statement a particular #endif terminates. This is particularly true because preprocessor directives are rarely indented, so it can be hard to follow the flow of execution.

Macros

The other major use of the preprocessor is to define macros. The advantage of a macro is that it can be type-neutral (this can also be a disadvantage, of course), and it's inlined directly into the code, so there isn't any function call overhead. (Note that in C++, it's possible to get around both of these issues with templated functions and the inline keyword.) 

A macro definition is usually of the following form:
#define MACRO_NAME(arg1, arg2, ...) [code to expand to]
For instance, a simple increment macro might look like this:
#define INCREMENT(x) x++
They look a lot like function calls, but they're not so simple. There are actually a couple of tricky points when it comes to working with macros. First, remember that the exact text of the macro argument is "pasted in" to the macro. For instance, if you wrote something like this:
#define MULT(x, y) x * y
and then wrote
int z = MULT(3 + 2, 4 + 2);
what value do you expect z to end up with? The obvious answer, 30, is wrong! That's because what happens when the macro MULT expands is that it looks like this:
int z = 3 + 2 * 4 + 2;    // 2 * 4 will be evaluated first!
So z would end up with the value 13! This is almost certainly not what you want to happen. The way to avoid it is to force the arguments themselves to be evaluated before the rest of the macro body. You can do this by surrounding them by parentheses in the macro definition:
#define MULT(x, y) (x) * (y)
// now MULT(3 + 2, 4 + 2) will expand to (3 + 2) * (4 + 2)
But this isn't the only gotcha! It is also generally a good idea to surround the macro's code in parentheses if you expect it to return a value. Otherwise, you can get similar problems as when you define a constant. For instance, the following macro, which adds 5 to a given argument, has problems when embedded within a larger statement:
#define ADD_FIVE(a) (a) + 5

int x = ADD_FIVE(3) * 3;
// this expands to (3) + 5 * 3, so 5 * 3 is evaluated first
// Now x is 18, not 24!
To fix this, you generally want to surround the whole macro body with parentheses to prevent the surrounding context from affecting the macro body.
#define ADD_FIVE(a) ((a) + 5)

int x = ADD_FIVE(3) * 3;
On the other hand, if you have a multiline macro that you are using for its side effects, rather than to compute a value, you probably want to wrap it within curly braces so you don't have problems when using it following an if statement.
// We use a trick involving exclusive-or to swap two variables
#define SWAP(a, b)  a ^= b; b ^= a; a ^= b; 

int x = 10;
int y = 5;

// works OK
SWAP(x, y);

// What happens now?
if(x < 0)
    SWAP(x, y);
When SWAP is expanded in the second example, only the first statement, a ^= b, is governed by the conditional; the other two statements will always execute. What we really meant was that all of the statements should be grouped together, which we can enforce using curly braces:
#define SWAP(a, b)  {a ^= b; b ^= a; a ^= b;} 
Now, there is still a bit more to our story! What if you write code like so:
#define SWAP(a, b)  { a ^= b; b ^= a; a ^= b; }

int x = 10;
int y = 5;
int z = 4;

// What happens now?
if(x < 0)
    SWAP(x, y);
else
    SWAP(x, z); 
Then it will not compile because semicolon after the closing curly brace will break the flow between if and else. The solution? Use a do-while loop:
#define SWAP(a, b)  do { a ^= b; b ^= a; a ^= b; } while ( 0 )

int x = 10;
int y = 5;
int z = 4;

// What happens now?
if(x < 0)
    SWAP(x, y);
else
    SWAP(x, z); 
Now the semi-colon doesn't break anything because it is part of the expression. (By the way, note that we didn't surround the arguments in parentheses because we don't expect anyone to pass an expression into swap!)

More Gotchas

By now, you've probably realized why people don't really like using macros. They're dangerous, they're picky, and they're just not that safe. Perhaps the most irritating problem with macros is that you don't want to pass arguments with "side effects" to macros. By side effects, I mean any expression that does something besides evaluate to a value. For instance, ++x evaluates to x+1, but it also increments x. This increment operation is a side effect. 

The problem with side effects is that macros don't evaluate their arguments; they just paste them into the macro text when performing the substitution. So something like
#define MAX(a, b) ((a) < (b) ? (b) : (a))
int x = 5, y = 10;
int z = MAX(x++, y++);
will end up looking like this:
int x = (x++ < y++ ? y++ : x++)
The problem here is that y++ ends up being evaluated twice! The nasty consequence is that after this expression, y will have a value of 12 rather than the expected 11. This can be a real pain to debug!

Multiline macros

Until now, we've seen only short, one line macros (possibly taking advantage of the semicolon to put multiple statements on one line.) It turns out that by using a the "\" to indicate a line continuation, we can write our macros across multiple lines to make them a bit more readable. 

For instance, we could rewrite swap as
#define SWAP(a, b)  {                   \
                        a ^= b;         \
                        b ^= a;         \ 
                        a ^= b;         \
                    } 
Notice that you do not need a slash at the end of the last line! The slash tells the preprocessor that the macro continues to the next line, not that the line is a continuation from a previous line. 

Aside from readability, writing multi-line macros may make it more obvious that you need to use curly braces to surround the body because it's more clear that multiple effects are happening at once.

Advanced Macro Tricks

In addition to simple substitution, the preprocessor can also perform a bit of extra work on macro arguments, such as turning them into strings or pasting them together.

Pasting Tokens

Each argument passed to a macro is a token, and sometimes it might be expedient to paste arguments together to form a new token. This could come in handy if you have a complicated structure and you'd like to debug your program by printing out different fields. Instead of writing out the whole structure each time, you might use a macro to pass in the field of the structure to print. 

To paste tokens in a macro, use ## between the two things to paste together. 

For instance
#define BUILD_FIELD(field) my_struct.inner_struct.union_a.##field
Now, when used with a particular field name, it will expand to something like
my_struct.inner_struct.union_a.field1
The tokens are literally pasted together.

String-izing Tokens

Another potentially useful macro option is to turn a token into a string containing the literal text of the token. This might be useful for printing out the token. The syntax is simple--simply prefix the token with a pound sign (#).
#define PRINT_TOKEN(token) printf(#token " is %d", token)
For instance, PRINT_TOKEN(foo) would expand to
printf("<foo>" " is %d" <foo>)
(Note that in C, string literals next to each other are concatenated, so something like "token" " is " " this " will effectively become "token is this". This can be useful for formatting printf statements.) 

For instance, you might use it to print the value of an expression as well as the expression itself (for debugging purposes).
PRINT_TOKEN(x + y);

Avoiding Macros in C++

In C++, you should generally avoid macros when possible. You won't be able to avoid them entirely if you need the ability to paste tokens together, but with templated classes and type inference for templated functions, you shouldn't need to use macros to create type-neutral code. Inline functions should also get rid of the need for macros for efficiency reasons. (Though you aren't guaranteed that the compiler will inline your code.) 

Moreover, you should use const to declare typed constants rather than #define to create untyped (and therefore less safe) constants. Const should work in pretty much all contexts where you would want to use a #define, including declaring static sized arrays or as template parameters.

'프로그래밍 > C, C++' 카테고리의 다른 글

8진수, 16진수의 이해  (0) 2011.06.07
2진 트리 검색  (0) 2011.06.07
The C++ Modulus Operator  (0) 2011.06.07
Getting Random Values in C and C++ with Rand  (0) 2011.06.07
Formatting Cout Output in C++ using iomanip  (0) 2011.06.07

The C++ Modulus Operator

Take a simple arithmetic problem: what's left over when you divide 11 by 3? The answer is easy to compute: divide 11 by 3 and take the remainder: 2. But how would you compute this in a programming language like C or C++? It's not hard to come up with a formula, but the language provides a built-in mechanism, the modulus operator ('%'), that computes the remainder that results from performing integer division.
The modulus operator is useful in a variety of circumstances. It is commonly used to take a randomly generated number and reduce that number to a random number on a smaller range, and it can also quickly tell you if one number is a factor of another. 

If you wanted to know if a number was odd or even, you could use modulus to quickly tell you by asking for the remainder of the number when divided by 2.
#include <iostream>

using namespace std;

int main()
{
    int num;
    cin >> num;
    // num % 2 computes the remainder when num is divided by 2
    if ( num % 2 == 0 )
    {
        cout << num << " is even ";
    }

    return 0;
}
The key line is the one that performs the modulus operation: "num % 2 == 0". A number is even if and only if it is divisible by two, and a number is divisible by another only if there is no remainder. 

How could you use modulus to write a program that checks if a number is prime?

'프로그래밍 > C, C++' 카테고리의 다른 글

2진 트리 검색  (0) 2011.06.07
The C Preprocessor  (0) 2011.06.07
Getting Random Values in C and C++ with Rand  (0) 2011.06.07
Formatting Cout Output in C++ using iomanip  (0) 2011.06.07
Enumerated Types - enums  (1) 2011.06.07

Getting Random Values in C and C++ with Rand



Written by RoD

At some point in any programmer's life, he or she must learn how to get a random value, or values, in their program. To some this seems involved, difficult, or even beyond their personal ability. This, however, is simply not the case.

Randomizing of values is, at its most basic form, one of the easier things a programmer can do with the C++ language. I have created this short tutorial for Cprogramming.com to aid you in learning, constructing, and using the functions available to you to randomize values.

I will first start with an introduction to the idea of randomizing values, followed by a simple example program that will output three random values. Once a secure understanding of these concepts is in place (hopefully it will be), I will include a short program that uses a range of values from which the random values can be taken.

Ok, now that you know why this tutorial was written, and what it includes, you are ready to learn how to randomize values! So without further ado, let's get started, shall we?

Many programs that you will write require the use of random numbers. For example, a game such as backgammon requires a roll of two dice on each move. Since there are 6 numbers on each die, you could calculate each roll by finding a random number from 1 to 6 for each die.

To make this task a little easier, C++ provides us with a library function, called rand that returns an integer between 0 and RAND_MAX. Let's take a break to explain what RAND_MAX is. RAND_MAX is a compiler-dependent constant, and it is inclusive. Inclusive means that the value of RAND_MAX is included in the range of values. The function, rand, and the constant, RAND_MAX, are included in the library header file stdlib.h.

The number returned by function rand is dependent on the initial value, called a seed that remains the same for each run of a program. This means that the sequence of random numbers that is generated by the program will be exactly the same on each run of the program.

How do you solve this problem you ask? Well I'll tell you! To help us combat this problem we will use another function, srand(seed), which is also declared in the stdlib.h header file. This function allows an application to specify the initial value used by rand at program startup.

Using this method of randomization, the program will use a different seed value on every run, causing a different set of random values every run, which is what we want in this case. The problem posed to us now, of course, is how to get an arbitrary seed value. Forcing the user or programmer to enter this value every time the program was run wouldn't be very efficient at all, so we need another way to do it.

So we turn to the perfect source for our always-changing value, the system clock. The C++ data type time_t and the function time, both declared in time.h, can be used to easily retrieve the time on the computers clock.

When converted to an unsigned integer, a positive whole number, the program time (at execution of program) can make a very nice seed value. This works nicely because no two program executions will occur at the same instant of the computers clock.

As promised, here is a very basic example program. The following code was written in Visual C++ 6.0, but should compile fine on most computers (given u have a compiler, which if your reading this I assume you do). The program outputs three random values.

/*Steven Billington
January 17, 2003
Ranexample.cpp
Program displays three random integers.
*/
/*
Header: iostream
Reason: Input/Output stream
Header: cstdlib
Reason: For functions rand and srand
Header: time.h
Reason: For function time, and for data type time_t
*/
#include <iostream>
#include <cstdlib>
#include <time.h>

using namespace std;

int main()
{
/*
Declare variable to hold seconds on clock.
*/
time_t seconds;
/*
Get value from system clock and
place in seconds variable.
*/
time(&seconds);
/*
Convert seconds to a unsigned
integer.
*/
srand((unsigned int) seconds);
/*
Output random values.
*/
cout<< rand() << endl;
cout<< rand() << endl;
cout<< rand() << endl;
return 0;
}

Users of a random number generator might wish to have a narrower or a wider range of numbers than provided by the rand function. Ideally, to solve this problem a user would specify the range with integer values representing the lower and the upper bounds. To understand how we might accomplish this with the rand function, consider how to generate a number between 0 and an arbitrary upper bound, referred to as high, inclusive.

For any two integers, say a and b, a % b is between 0 and b - 1, inclusive. With this in mind, the expression rand() % high + 1 would generate a number between 1 and high, inclusive, where high is less than or equal to RAND_MAX, a constant defined by the compiler. To place a lower bound in replacement of 1 on that result, we can have the program generate a random number between 0 and (high - low + 1) + low.

I realize how confused you might be right now, so take a look at the next sample program I promised, run it, toy with it, and alternate it to give you different values. It has been a pleasure to teach you another chapter in the world of C++, and you may feel free to email me at Silent_Death17@hotmail.com or to contact me on the message boards of this fine website, where I use the name RoD.

Enjoy, and happy programming!
/*
Steven Billington
January 17, 2003
exDice.cpp
Program rolls two dice with random
results.
*/
/*
Header: iostream
Reason: Input/Output stream
Header: stdlib
Reason: For functions rand and srand
Header: time.h
Reason: For function time, and for data type time_t
*/
#include <iostream>
#include <cstdlib>
#include <time.h>
/*
These constants define our upper
and our lower bounds. The random numbers
will always be between 1 and 6, inclusive.
*/
const int LOW = 1;
const int HIGH = 6;

using namespace std;

int main()
{
/*
Variables to hold random values
for the first and the second die on
each roll.
*/
int first_die, sec_die;
/*
Declare variable to hold seconds on clock.
*/
time_t seconds;
/*
Get value from system clock and
place in seconds variable.
*/
time(&seconds);
/*
Convert seconds to a unsigned
integer.
*/
srand((unsigned int) seconds);
/*
Get first and second random numbers.
*/
first_die = rand() % (HIGH - LOW + 1) + LOW;
sec_die = rand() % (HIGH - LOW + 1) + LOW;
/*
Output first roll results.
*/
cout<< "Your roll is (" << first_die << ", "
<< sec_die << "}" << endl << endl;
/*
Get two new random values.
*/
first_die = rand() % (HIGH - LOW + 1) + LOW;
sec_die = rand() % (HIGH - LOW + 1) + LOW;
/*
Output second roll results.
*/
cout<< "My roll is (" << first_die << ", "
<< sec_die << "}" << endl << endl;
return 0;
}


'프로그래밍 > C, C++' 카테고리의 다른 글

The C Preprocessor  (0) 2011.06.07
The C++ Modulus Operator  (0) 2011.06.07
Formatting Cout Output in C++ using iomanip  (0) 2011.06.07
Enumerated Types - enums  (1) 2011.06.07
Class Design in C++ : Understanding Interfaces  (0) 2011.06.07

Formatting Cout Output in C++ using iomanip

Creating cleanly formatted output is a common programming requirement--it improves your user interface and makes it easier to read any debugging messages that you might print to the screen. In C, formatted output works via the printf statement, but in C++, you can create nicely formatted output to streams such as cout. This tutorial covers a set of basic I/O manipulations possible in C++ from the iomanip header file. Note that all of the functions in the iomanip header are inside the std *namespace, so you will need to either prefix your calls with "std::" or put "using namespace std;" before using the functions. 


Dealing with Spacing Issues using iomanip

A principle aspect of nicely formatted output is that the spacing looks right. There aren't columns of text that are too long or too short, and everything is appropriately aligned. This section deals with ways of spacing output correctly.

Setting the field width with setw

The std::setw function allows you to set the minimum width of the next output via the insertion operator. setw takes, one argument, the width of the next output (insertion), an integer. if the next output is too short, then spaces will be used for padding. There is no effect if the output is longer than the width--note that the output won't be truncated. The only strange thing about setw is that its return value must be inserted into the stream. The setw function has no effect if it is called without reference to a stream. A simple example is
using namespace std;cout<<setw(10)<<"ten"<<"four"<<"four";
The output from the above would look like this:
ten       fourfour
Note that since setw takes an argument, at runtime it would be possible to specify the width of a column of output so that it is slightly wider than the longest element of the column. 

You might wonder whether it is possible to change the padding character. It turns out that yes, you can, by using the setfill function, which takes a character to use for the padding. Note that setfill should also be used as a stream manipulator only, so it must be inserted into the stream:
cout<<setfill('-')<<setw(80)<<"-"<<endl;
The above code sets the padding character to a dash, the width of the next output to be at least 80 characters, and then outputs a dash. This results in the rest of the line being filled with dashes too. The output would look like this:
--------------------------------------------------------------------------------
Note that the pad character is changed until the next time you call setfill to change it again.

Aligning text with iomanip

It's possible to specify whether output is left or right aligned by using the manipulator flags that are part of ios_bas. In particular, it is possible to specify that output should be either left or right aligned by passing in the stream manipulators std::left and std::right.

Putting Your Knowledge of iomanip Together

Now that we know how to space and align text, we can correctly print formatted data in columns. For instance, if you had a struct containing the names of individuals:
using namespace std;struct person{    string firstname;    string lastname;};
If you then had a vector of persons, then you could output them in a nice way with evenly spaced columns for the first and last name as follows:
// given the above code, we could write thisvector<person> people;// fill the vector somehowint field_one_width = 0, field_two_width = 0;// get the max widthsfor ( vector<person>::iterator iter = people.begin();      iter != people.end();      ++iter ){    if ( iter->firstname.length() > field_one_width )    {        field_one_width = iter->firstname.length();    }    if ( iter->lastname.length() > field_two_width )    {        field_two_width = iter->lastname.length();    }}// print the elements of the vectorfor ( vector<person>::iterator iter = people.begin();      iter != people.end();      ++iter ){    cout<<setw(field_one_width)<<left<<iter->firstname;    cout<<" ";    cout<<setw(field_two_width)<<left<<iter->lastname;}
Note that the space output between the two fields wasn't strictly necessary because we could have added it by changing the first call to setw to set the width to one more than the longest first name (since it would use a space as the padding for the extra character).

Printing Numbers

Another challenge in creating nice output is correctly formatting numbers; for instance, when printing out a hexadecimal value, it would be nice if it were preceded by the "0x" prefix. More generally, it's nice to correctly set the number of trailing zeros after a decimal place.

Setting the precision of numerical output with setprecision

The setprecision function can be used to set the maximum number of digits that are displayed for a number. Like setw, it should be inserted into the stream. In fact, its usage is very similar to setw in all respects. For instance, to print the number 2.71828 to 3 decimal places:
std::cout << setprecision(3) << 2.71828;
Note that setprecision will change the precision until the next time it is passed into a given stream. So changing the above example to also print out 1.412 would result in the output of
2.71 1.41

Output in different bases

In computer science, frequently numbers need to be printed in octal or hexadecimal. The setbase function returns a value that can be passed into a stream to set the base of numbers to either base 8, 10, or 16. The input number is still read as a number in base ten, but it is printed in the given base. For instance,
std::cout << setbase(16) << 32;
will print out "20", which is 32 written in base 16. Note that you can use dec, oct, and hex as shorthand for setbase(10), setbase(8), and setbase(16) respectively when inserting into a stream. If you wish to include an indication of the base along with the printed number, you can use the setiosflags function, again passed into a stream, with an input of ios_base::showbase. Using the ios_base::showbase flag will append a "0x" in front of hexadecimal numbers and a 0 in front of octal numbers. Decimal numbers will be printed as normal.
std::cout << setbase(16) << 32;
This should get you started with the ability to create nicely formatted output in C++ without having to resort to returning to printf!




*namespace
 



Enumerated Types - enums

Sometimes as programmers we want to express the idea that a variable will be used for a specific purpose and should only be able to have a small number of values--for instance, a variable that stores the current direction of the wind might only need to store values corresponding to north, south, east, and west. One solution to this problem might be to use an int and some #define'd values:
#define NORTH_WIND        0
#define SOUTH_WIND        1
#define EAST_WIND         2
#define WEST_WIND         3     
#define NO_WIND           4       

int wind_direction = NO_WIND;
The problem with this approach is that it doesn't really prevent someone from assigning a nonsensical value to wind_direction; for instance, I could set wind_direction to 453 without any complaints from my compiler. And if I looked at the type of wind_direction, i would see that it's just a plain old integer. there's just no way to know that something is wrong. 

The idea behind enumerated types is to create new data types that can take on only a restricted range of values. Moreover, these values are all expressed as constants rather than magic numbers--in fact, there should be no need to know the underlying values. The names of the constants should be sufficient for the purposes of comparing values. 

When you declare an enumerated type, you specify the name of the new type, and the possible values it can take on:
enum wind_directions_t {NO_WIND, NORTH_WIND, SOUTH_WIND, EAST_WIND, WEST_WIND};
Note the _t at the end of the name of the type: this stands for "type" and is a way to visually distinguish the name of the type from the name of variables. Your text editor(vi,vim,notpad++) may also have the ability to use syntax highlighting to make the new type look like other built-in types, such as int, for you. 

Now we can declare a wind_directions_t variable that can only take on five values:
wind_directions_t wind_direction = NO_WIND;

wind_direction = 453; // doesn't work, we get a compiler error!
Note to C Programmers: If you're planning on using enums in C, however, you don't get this type safety. The above assignment will compile without giving you an error. By the way, if you're using enums in C, you will also need to prefix the declaration with the keyword enum: enum wind_directions_t wind_direction = NO_WIND; 

You might be wondering exactly what values the constants take on--what if you wanted to compare then using < or >? You actually have a choice: if you want to set the values yourself, you may, or you can choose to use default values, which start at zero for the first constant and increase by one. In our example, NO_WIND has the value 0, and WEST_WIND has the value 4 (just like our #define'd constants). 

On the other hand, we could reverse this by giving explicit values:
enum wind_directions_t {NO_WIND = 4, NORTH_WIND = 3, SOUTH_WIND = 2, EAST_WIND = 1, WEST_WIND = 0};
Why would you ever want to give explicit values to elements of an enumerated type? Isn't the whole point of constants so that you don't need to know what the values are? The answer is that if the values of the constant are never used outside of comparisons between elements of the enumeration, then there's almost no reason to define the values to be anything in particular (one exception is if you want one value to have multiple names, you'd have to set at least one value explicitly). But if you need the values for communicating with the outside world, you might need to give specific values. For example, if you decided to use an enum to store all of the possible text colors you could pass into a function to set the text colors, you'd probably need to make sure that the enum names, such a RED or BLUE, matched up to the values corresponding to those colors.

Printing Enums

You might wonder what happens when you print out an enum: by default, you'll get the integer value of the enum. If you want to do something fancier than that, you'll have to handle it specially.

Naming Enums

One issue with enums is that the name of the enumerated type doesn't show up along with the enum. When you use the enum constant, it could really mean anything. The problem is that if you give your enums names that are too general, you can run into problems. First, it becomes hard to tell which enumeration a constant belongs to if you have several enumerated lists of values. A related problem is that sometimes you really want to use the same name. For instance, what if you had two color schemes, each of which included the color red, but for which the value of the RED constant needed to be different? 

The solution to both of these problems is to include part of the name of the enum in the names of the constants. Notice that in the above example, I included "WIND" in the name of each enumerated constant. (Perhaps this wasn't entirely necessary--why not just have an enum for each ordinal direction? The answer is that it depends on whether someone else is already using the name. In this case, we avoid the problem by making the names specific enough that it's unlikely someone else will have a WEST_WIND constant.

Type Correctness

Because enums are "integer-like" types, they can safely be assigned into an integer without a cast. For instance, both of the following assignments are totally valid:
int my_wind = EAST_WIND;
or
wind_directions_t wind_direction = NO_WIND;

int my_wind = wind_direction;
As already mentioned, you can't make the reverse assignment in C++ without using a typecast. There might be times when you do need to do this, but you'd like to avoid it as best you can. For instance, if you need to convert a user's input into an enumerated type, it would be a bad idea to just typecast the variable to an int:
wind_directions_t wind_direction = NO_WIND;

std::cin >> static_cast( wind_direction );
This would let the user input any value at all and, almost as bad, force the user to know the range of values that the enum could take on. A much better solution would be to shield the user from the enumeration by asking for a string and then validating the input by comparing it to the possible input strings to choose which constant to assign the enum. For instance,
std::cout << "Please enter NORTH, SOUTH, EAST, WEST, or NONE for our wind direction";
std::cout << std::endl;

string input_wind_dir;
cin >>

wind_directions_t wind_dir;

if ( user_wind_dir == "NORTH" )
{
        wind_dir = NORTH_WIND;
}
else if ( user_wind_dir == "SOUTH" )
{
        wind_dir = SOUTH_WIND;
}
else if ( user_wind_dir == "EAST" )
{
        wind_dir = EAST_WIND;
}
else if ( user_wind_dir == "WEST" )
{
        wind_dir = WEST_WIND;
}
else if ( user_wind_dir == "NONE" )
{
        wind_dir = NO_WIND;
}
else
{
        std::cout << "That's not a valid direction!" << std::endl;
}

Polymorphic Enums?

In C++, we often use polymorphism to allow old code to handle new code--for instance, as long as we subclass the interface expected by a function, we can pass in the new class and expect it to work correctly with the code that was written before the new class ever existed. Unfortunately, with enums, you can't really do this, even though there are occasional times you'd like to. (For instance, if you were managing the settings for your program and you stored all of them as enum values, then it might be nice to have an enum, settings_t, from which all of your other enums inherited so that you could store every new enum in the settings list. Note that since the list contains values of different types, you can't use *templates.) 

If you need this kind of behavior, you're forced to store the enums as integers and then retrieve them using typecasts to assign the particular value to the setting of interest. And you won't even get the benefit of dynamic_cast to help you ensure that the cast is safe--you'll have to rely on the fact that incorrect values cannot be stored in the list.

Summary

The Good

  • Enums allow you to constrain the values a variable takes on
  • Enums can be used to make your program more readable by eliminating magic numbers are specifying exact what range of values a variable expects to take on
  • Enums can be used to quickly declare a range of constant values without using #define

The Gotchas

  • Enum constants must be carefully named to avoid name collisions
  • Enums don't work "polymorphically" except from the int type, which can be inconvenient


     

*templates

Class Design in C++

Understanding Interfaces

When you're designing a class in C++, the first thing you should decide is the public interface for the class. The public interface determines how your class will be used by other programmers (or you), and once designed and implemented it should generally stay pretty constant. You may decide to add to the interface, but once you've started using the class, it will be hard to remove functions from the public interface (unless they aren't used and weren't necessary in the first place). 

But that doesn't mean that you should include more functionality in your class than necessary just so that you can later decide what to remove from the interface. If you do this, you'll just make the class harder to use. People will ask questions like, "why are there four ways of doing this? Which one is better? How can I choose between them?" It's usually easier to keep things simple and provide one way of doing each thing unless there's a compelling reason why your class should offer multiple methods with the same basic functionality. 

At the same time, just because adding methods to the public interface (probably) won't break anything that doesn't mean that you should start off with a tiny interface. First of all, if anybody decides to inherit from your class and you then choose a function with the same name, you're in for a boatload of confusion. First, if you don't declare the function virtual, then an object of the subclass will have the function chosen depending on the static type of the pointer. This can be messy. Moreover, if you do declare it virtual, then you have the issue that it might provide a different type of functionality than was intended by the original implementation of that function. Finally, you just can't add a pure virtual function to a class that's already in use because nobody who has inherited from it will have implemented that function. 

The public interface, then, should remain as constant as possible. In fact, a good approach to designing classes is to write the interface before the implementation because it's what determines how your class interacts with the rest of the world (which is more important for the program as a whole than how the class is actually implemented). Moreover, if you write the interface first, you can get a feel for how the class will work with other classes before you actually dive into the implementation details.

Inheritance and Class Design

The second issue of your class design is what should be available to programmers who wish to create subclasses. This interface is primarily determined by virtual functions, but you can also include protected methods that are designed for use by the class or its subclasses (remember that protected methods are visible to subclasses while private methods are not). 

A key consideration is whether it makes sense for a function to be virtual. A function should be virtual when the implementation is likely to differ from subclass to subclass. Vice-versa, whenever a function should not change, then it should be made non-virtual. The key idea is to think about whether to make a function virtual by asking if the function should always be the same for every class. 

For example, if you have a class is designed to allow users to monitor network traffic and you want to allow subclasses that implement different ways of analyzing the traffic, you might use the following interface:
class TrafficWatch
{
        public:
        // Packet is some class that implements information about network
        // packets
        void addPacket (const Packet& network_packet);

        int getAveragePacketSize ();

        int getMaxPacket ();

        virtual bool isOverloaded ();
};
In this class, some methods will not change from implementation to implementation; adding a packet should always be handled the same way, and the average packet size isn't going to change either. On the other hand, someone might have a very different idea of what it means to have an overloaded network. This will change from situation to situation and we don't want to prevent someone from changing how this is computed--for some, anything over 10 Mbits/sec of traffic might be an overloaded network, and for others, it would require 100 Mbits/sec on some specific network cables. 

Finally, when publicly inheriting from any class or designing for inheritance, remember that you should strive for it to be clear that inheritance models is-a. At heart, the is-a relationship means that the subclass should be able to appear anywhere the parent class could appear. From the standpoint of the user of the class, it should not matter whether a class is the parent class or a subclass. 

To design an is-a relationship, make sure that it makes sense for the class to include certain functions to be sure that it doesn't include that subclasses might not actually need. One example of having an extra function is that of a Bird class that implements a fly function. The problem is that not all birds can fly--penguins and emus, for instance. This suggests that a more prudent design choice might be to have two subclasses of birds, one for birds that can fly and one for flightless birds. Of course, it might be overkill to have two subclasses of bird depending on how complex your class hierarchy will be. If you know that nobody would ever expect use your class for a flightless bird, then it's not so bad. Of course, you won't always know what someone will use your class for and it's much easier to think carefully before you start to implement an entire class hierarchy than it will be to go back and change it once people are using it.


Understanding Initialization Lists in C++

Understanding the Start of an Object's Lifetime

In C++, whenever an object of a class is created, its constructor is called. But that's not all--its parent class constructor is called, as are the constructors for all objects that belong to the class. By default, the constructors invoked are the default ("no-argument") constructors. Moreover, all of these constructors are called before the class's own constructor is called. 

For instance, take the following code:
#include <iostream>
class Foo
{
        public:
        Foo() { std::cout << "Foo's constructor" << std::endl; }
};
class Bar : public Foo
{
        public:
        Bar() { std::cout << "Bar's constructor" << std::endl; }
};

int main()
{
        // a lovely elephant ;)
        Bar bar;
}
The object bar is constructed in two stages: first, the Foo constructor is invoked and then the Bar constructor is invoked. The output of the above program will be to indicate that Foo's constructor is called first, followed by Bar's constructor. 

Why do this? There are a few reasons. First, each class should need to initialize things that belong to it, not things that belong to other classes. So a child class should hand off the work of constructing the portion of it that belongs to the parent class. Second, the child class may depend on these fields when initializing its own fields; therefore, the constructor needs to be called before the child class's constructor runs. In addition, all of the objects that belong to the class should be initialized so that the constructor can use them if it needs to. 

But what if you have a parent class that needs to take arguments to its constructor? This is where initialization lists come into play. An initialization list immediately follows the constructor's signature, separated by a colon:
class Foo : public parent_class
{
        Foo() : parent_class( "arg" ) // sample initialization list
        {
                // you must include a body, even if it's merely empty
        }
};
Note that to call a particular parent class constructor, you just need to use the name of the class (it's as though you're making a function call to the constructor). 

For instance, in our above example, if Foo's constructor took an integer as an argument, we could do this:
#include <iostream>
class Foo
{
        public:
        Foo( int x ) 
        {
                std::cout << "Foo's constructor " 
                          << "called with " 
                          << x 
                          << std::endl; 
        }
};

class Bar : public Foo
{
        public:
        Bar() : Foo( 10 )  // construct the Foo part of Bar
        { 
                std::cout << "Bar's constructor" << std::endl; 
        }
};

int main()
{
        Bar stool;
}

Using Initialization Lists to Initialize Fields

In addition to letting you pick which constructor of the parent class gets called, the initialization list also lets you specify which constructor gets called for the objects that are fields of the class. For instance, if you have a string inside your class:
class Qux
{
        public:
                Qux() : _foo( "initialize foo to this!" ) { }
                // This is nearly equivalent to 
                // Qux() { _foo = "initialize foo to this!"; }
                // but without the extra call to construct an empty string

        private:
        std::string _foo;
};
Here, the constructor is invoked by giving the name of the object to be constructed rather than the name of the class (as in the case of using initialization lists to call the parent class's constructor). 

If you have multiple fields of a class, then the names of the objects being initialized should appear in the order they are declared in the class (and after any parent class constructor call):
class Baz
{
        public:
                Baz() : _foo( "initialize foo first" ), _bar( "then bar" ) { }

        private:
        std::string _foo;
        std::string _bar;
};

Initialization Lists and Scope Issues

If you have a field of your class that is the same name as the argument to your constructor, then the initialization list "does the right thing." For instance,
class Baz
{
        public:
                Bar( std::string foo ) : foo( foo ) { }
        private:
            std::string foo;
};
is roughly equivalent to
class Baz
{
        public:
                Bar( std::string foo )
                {
                    this->foo = foo;
                }
        private:
            std::string foo;
};
That is, the compiler knows which foo belongs to the object, and which foo belongs to the function.

Initialization Lists and Primitive Types

It turns out that initialization lists work to initialize both user-defined types (objects of classes) and primitive types (e.g., int). When the field is a primitive type, giving it an argument is equivalent to assignment. For instance,
class Quux
{
        public:
                Quux() : _my_int( 5 )  // sets _my_int to 5
                { }

        private:
                int _my_int;
};
This behavior allows you to specify templates where the templated type can be either a class or a primitive type (otherwise, you would have to have different ways of handling initializing fields of the templated type for the case of classes and objects).
template 
class my_template
{
        public:
                // works as long as T has a copy constructor
                my_template( T bar ) : _bar( bar ) { }

        private:
                T _bar;
};

Initialization Lists and Const Fields

Using initialization lists to initialize fields is not always necessary (although it is probably more convenient than other approaches). But it is necessary for const fields. If you have a const field, then it can be initialized only once, so it must be initialized in the initialization list.
class const_field
{
        public:
                const_field() : _constant( 1 ) { }
                // this is an error: const_field() { _constant = 1; } 

        private:
                const int _constant;
};

When Else do you Need Initialization Lists?

No Default Constructor

If you have a field that has no default constructor (or a parent class with no default constructor), you must specify which constructor you wish to use.

References

If you have a field that is a reference, you also must initialize it in the initialization list; since references are immutable they can be initialized only once.

Initialization Lists and Exceptions

Since constructors can throw exceptions, it's possible that you might want to be able to handle exceptions that are thrown by constructors invoked as part of the initialization list. 

First, you should know that even if you catch the exception, it will get rethrown because it cannot be guaranteed that your object is in a valid state because one of its fields (or parts of its parent class) couldn't be initialized. That said, one reason you'd want to catch an exception here is that there's some kind of translation of error messages that needs to be done. 

The syntax for catching an exception in an initialization list is somewhat awkward: the 'try' goes right before the colon, and the catch goes after the body of the function:
class Foo
{
        Foo() try : _str( "text of string" ) 
        { 
        } 
        catch ( ... ) 
        { 
                std::cerr << "Couldn't create _str";
                // now, the exception is rethrown as if we'd written
                // "throw;" here
        }
};

Initialization Lists: Summary

Before the body of the constructor is run, all of the constructors for its parent class and then for its fields are invoked. By default, the no-argument constructors are invoked. Initialization lists allow you to choose which constructor is called and what arguments that constructor receives. 

If you have a reference or a const field, or if one of the classes used does not have a default constructor, you must use an initialization list.

Lesson 20: Inheritance - Syntax

Before beginning this lesson, you should have an understanding of the idea of inheritance. If you do not, please read lesson 19. This lesson will consist of an overview of the syntax of inheritance, the use of the keywords public, private, and protected, and then an example program following to demonstrate each. 


The syntax to denote one class as inheriting from another is simple. It looks like the following: class Bear : public Animal, in place of simply the keyword class and then the class name. The ": public base_class_name" is the essential syntax of inheritance; the function of this syntax is that the class will contain all public and protected variables of the base class. Do not confuse the idea of a derived class having access to data members of a base class and specific instances of the derived class possessing data. The data members - variables and functions - possessed by the derived class are specific to the type of class, not to each individual object of that type. So, two different Bear objects, while having the same member variables and functions, may have different information stored in their variables; furthermore, if there is a class Animal with an object, say object BigAnimal, of that type, and not of a more specific type inherited from that class, those two bears will not have access to the data within BigAnimal. They will simply possess variables and functions with the same name and of the same type. 

A quick example of inheritance:
class Animal
{
  public:
  Animal();
  ~Animal();
  void eat();
  void sleep();
  void drink();

private:
  int legs;
  int arms;
  int age;
};
//The class Animal contains information and functions
//related to all animals (at least, all animals this lesson uses)
class Cat : public Animal
{
  public:
  int fur_color;
  void purr();
  void fish();
  void markTerritory();
};
//each of the above operations is unique
//to your friendly furry friends
//(or enemies, as the case may be)
A discussion of the keywords public, private, and protected is useful when discussing inheritance. The three keywords are used to control access to functions and variables stored within a class.

public:

The most open level of data hiding is public. Anything that is public is available to all derived classes of a base class, and the public variables and data for each object of both the base and derived class is accessible by code outside the class. Functions marked public are generally those the class uses to give information to and take information from the outside world; they are typically the interface with the class. The rest of the class should be hidden from the user using private or protected data (This hidden nature and the highly focused nature of classes is known collectively as encapsulation). The syntax for public is:
public:
Everything following is public until the end of the class or another data hiding keyword is used. 

In general, a well-designed class will have no public fields--everything should go through the class's functions. Functions that retrieve variables are known as 'getters' and those that change values are known as 'setters'. Since the public part of the class is intended for use by others, it is often sensible to put the public section at the top of the class.

protected:

Variables and functions marked protected are inherited by derived classes; however, these derived classes hide the data from code outside of any instance of the object. Keep in mind, even if you have another object of the same type as your first object, the second object cannot access a protected variable in the first object. Instead, the second object will have its own variable with the same name - but not necessarily the same data. Protected is a useful level of access control for important aspects to a class that must be passed on without allowing it to be accessed. The syntax is the same as that of public. specifically,
 protected: 

private:

Private is the highest level of data-hiding. Not only are the functions and variables marked private not accessible by code outside the specific object in which that data appears, but private variables and functions are not inherited (in the sense that the derived class cannot directly access these variables or functions). The level of data protection afforded by protected is generally more flexible than that of the private level. On the other hand, if you do not wish derived classes to access a method, declaring it private is sensible.
 private: 

+ Recent posts