Features


Some Small C++ Classes

Joe Schell


Joe Schell received his B.A. in mathematics from the University of Colorado. He has been programming 15 years as a hobby, five of those years in C. Joe specializes in writing C/C+ + libraries. You can contact him at P.O. Box 7039, Boulder, CO 80306.

I have read a number of books and articles on C++. All of them have code in them, but none of them seem to have any small classes that are useful. I define a small class as one that is solely contained in the header file. Additionally the methods (the functions of the class) should be simple and will probably compile as in-line code.

Here are a few small classes that should be useful. I will describe four classes: boolean, byte, word, and check_heap. The first handles true and false values. byte and word handle 8-bit and 16-bit values that are found in memory. check_heap is a debugging tool that determines if constructors and destructors are handling memory allocation correctly.

boolean Class

I modeled the boolean class on the boolean type in Pascal. The implementation was easy, and the code should be mostly self-explanatory. I did have some doubts over some implementation details. Initially I was going to make the ++ force the boolean to true and the ­ ­ operator force it to false. But that didn't add anything since the programmer could simply set the Boolean value if he wants to force it to a specific value. So, instead these two operators reverse the value of the Boolean.

In Pascal, the true and false values are constant. The const keyword does the same thing for the C+ + values. The only methods that can be called for a const boolean are operator int( ), operator ~( ), and make_string. Those methods are defined as constant by the use of const in front of the function definition and because they don't modify the Boolean value.

Initially, the make_string method was actually implemented as the conversion operator for char*: operator char*( ). Although this method seems intuitive, C++ v2.0 does not have a precedence order for picking an int conversion over a char* conversion in conditional statements.

Most of my code in the last two years has used Booleans in conditionals — although I have never printed true/false. So the choice of the conversion operator was easy. It is interesting to look at the line false = true; in testbool.cpp. Because true is a constant, that line should produce an error message. In Turbo C++, it produces a warning message. A similar line using a const int does produce an error message. The code for the boolean class is in boolean.hpp. The test routine testbool.cpp will check it.

check_heap Class

I developed the next class while I was working on some constructors and destructors that allocated and deallocated memory. I needed to test that the heap was being handled correctly after the destructors were called. Because I had several different simultaneous tests, a class was the perfect way to handle it. Look at the file testheap.cpp for several examples

The check_heap variable is declared at the beginning of a suspected problem area. The method test is called any number of times after that. test will send an error message to cerr if the heap is different than when an instance of the class is declared. I found this useful even in places where I knew that the heap was supposed to be different. When using this class, keep in mind that it is often useful to pass a class instance to a function as the following line does in testheap.cpp.

test_value(t);
Don't forget that main creates a temporary value for t. It is this temporary value that actually gets passed to test_value. Because the destructor for the temporary doesn't get called until the end of main, an error message is produced. (Even after two years of using C++ and the check_heap class, I still forget this detail all the time.) The best way to avoid the problem is to insert another function call level into the code. You can use test_test_value. The temporary value is created inside this function and destroyed before it returns.

If there is a problem when test is called, the function will print out the difference from when it started and the current position. I seldom find that number of any real use, but it has helped me occasionally when I had no idea where the problem was. I just start poking at random items until the difference changes by a little bit. Then I know I am in the right area.

Since that difference can be useful, I spent a lot of time making sure that the number it printed made some kind of sense. PC compatibles use a segmented memory structure, so the code must adjust for different memory models. The macro CHECK_HEAP_diff_ makes this adjustment. It is possible that test will not be inlined even though it looks as though it should be. However, it is certainly not worth the effort of keeping it in a separate source file. I prefer to keep it all in the header file. The code for check_heap is in chkheap.hpp.

byte And word Classes

The last two classes are byte and word. These classes could almost be implemented as typedefs, except that they check for valid values. byte is used just like an unsigned char.word is used just like an unsigned int. If a larger value is assigned to either one, then an error message is generated at runtime. In the test code testbyte.cpp, byte is used like a pointer to char, and word is used like a pointer to int. For example:

d = (byte*)test_byte;
...
z = (word*)(&test_word);
This is permissible only when the byte class is the same size as a char and the word class is the same size as an int. In particular, the byte class will not work on a 286 or 386 when word alignment is used. To check the size I have included the two #if directives that are at the end of the byte.hpp file. They will produce a compile-time error if the sizes do not match. I would probably not use these as pointers to ints or chars though. They are intended to point to various locations directly in memory, as when you access data for the serial ports or the keyboard directly. Note that on PC compatibles, these can also be used as far pointers in the following manner:

byte far *b = far_address_of_byte;

Some Final Comments

I find the file form.h to be useful. It does not contain any classes, and it is only needed for the function form. I haven't found any way to use the Turbo C++ form function and still use iostream.h, so I made my own function.

I use the following naming scheme for my files. The extension hpp is used for include files which have classes in them. The extensions h and hh are used as they are in C. The extension cpp indicates a C++ source file, containing either classes or final applications such as the testing routines. The c extension is used for C code only. I make this distinction because I write in C and C++, and I need to keep the two separate. In addition, when I am looking through code I want to be able to distinguish between include files with classes and those without classes. These distinctions make life a little easier for me.

Listing 1

Listing 2

Listing 3

Listing 4

Listing 5

Listing 6

Listing 7