The object-orientation of the code is the major enhancement to my program. A C program is made up of data and functions. Many different data types are available and data structures can be declared as custom data types. Typically a function is passed one or more variables, the function then operates on the variables, and control is returned to the calling code. In complex code, this can lead to confusion when similar, but different, functions are used to operate on similar, but different, data.
C++ gets around this problem by combining data and functions into one entity called an object. The definition of an object is called a class. A C++ class is very similar to a C data structure. It contains data, but it also contains functions. A function that appears as part of an object is called a method. Thus, an object contains both the data it needs and the code to act on this data all in one place. If a program needs to tell an object to do something, it simply calls one of the object's methods. A typical example is a vector-based graphics program that allows geometric shapes to be drawn on the screen. Each geometric shape could be an object created from a class definition. When an actual object is created in computer memory from a class definition, this is called instantiation, or creating an instance of a class. The object might contain a ChangeColor method. If the object's name is GeoShape1, then something like the following statement could be used to change its color to red: GeoShape1.ChangeColor(RED).
Typically, when defining an object in C++, two files are created: the header (.hpp) file and the code (.cpp) file. The header file, also called the definition file, contains all the #include's, #define's, structure definitions, etc. as well as the class definition. The code file, also called the implementation file contains all the methods' code. By separating the code in this way, any program that needs to use an object can simply #include the header file and the object will be available to it. It is recommended that each object have its own header and code file. This allows one object to be changed without having to recompile any other objects.
Listing 1 contains the header file (FuncEval.hpp) for the FuncEval object. Notice that all the syntax error definitions have been incorporated into this file. They were separate in the C version. The structure definitions CharStackType and NumStackType are the same as the CharStack and NumStack definitions in the C code. It is highly recommended that when defining a structure, StructName, that the structure be named StructNameType. Immediately following the definition, a typedef statement should be used to define StructName as a new variable of type StructNameType. This is what I have done for CharStack and NumStack.
The actual class definition for FuncEval appears at the end of Listing 1. Notice that the data and methods are divided into public and private. Public data and methods can be used by an outside program, whereas private data and methods cannot. Private data and methods can only be used by the methods within the object. Generally, it is not recommended that any data be public, only methods. If data needs to be changed by a program, it should do so through a public method. In the example of the geometric shape object, the color was changed by calling a method; however, it could have been done by making the color variable public and letting the program execute the following statement: GeoShape1.Color=RED. By using a method to change the color, new features can be added to the object with no need to change the program that uses it. For the FuncEval class, all data and most methods are private. The public methods are used for converting a function string, getting an error number, message, and position, and evaluating the function for values of X and Y. When a public method has the same name as the class itself, it is called a constructor. This is a special method that executes each time the class is instantiated. The constructor is used for initializing variables and other tasks that need to be done before the object is used. Although the FuncEval class does not have one, a class can also have a destructor for cleaning up before an object is deleted. Its name is the same as the constructor but with a tilde (~) in front (e.g., ~FuncEval).
The code file for FuncEval is shown in Listing 2. All of the methods, except the constructor and the ones used for error handling, are the same as their equivalent functions in the C version with just a few exceptions. First, type casting is used in the methods to satisfy C++'s stronger type checking. Second, the method names are different than their equivalent function names. If the function name is CheckSyntax, then its equivalent method is named FuncEval::CheckSyntax. The "FuncEval::" prefix associates a method with the FuncEval class. Other objects can have a method with the same name. As for the constructor, it simply initializes the error position to zero.
Listing 3 shows a program, Main.cpp, that uses the FuncEval object to evaluate a user-defined 3D function. This program is similar to the Testfevl.c program in the October 1989 article. However, the code is somewhat different in order to interact with the FuncEval object properly. At the beginning of main() is the statement: FuncEval *func = new FuncEval. The new operator instantiates the FuncEval class, creating an actual instance of the FuncEval object in memory. The pointer to this object is named func. The rest of the program is easy to follow, but notice how FuncEval's public methods are called: func->PublicMethodName. The name of the pointer is used because the method is part of the object.
Sessions, Roger; Class Construction in C and C++: Object-Oriented Programming Fundamentals; PTR Prentice Hall, Inc.; 1992.