Advanced OOP using C++

A First Look at Classes

Published:  August 2, 2008
By Richard G. Baldwin

File:  AdvCpp00125


Preface

General

The purpose of this series of tutorial lessons is to help you to progress from procedural programming using C++ to object-oriented programming (OOP) using C++.  Although there are several introductory lessons preceding this one, this is the first lesson in the series that introduces you to executable OOP code.

Viewing tip

I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.

Figures

Listings

Supplementary material

I recommend that you also study the other lessons in my extensive collection of online programming tutorials.  You will find a consolidated index at www.DickBaldwin.com.

Preview

This lesson assumes that you already know something about structures and unions in the C programming language.  The lesson introduces you to the C++ extensions to the structure and the union and also introduces you to the C++ capability embodied in the class.

C++ structures are similar to C structures but they have more features. When you define a structure in C++, you have designed a new data type and added it to the language. In C++, a structure is its own data type and can be known by its own name without the struct keyword.

C++ provides major support for the concept of encapsulation by extending the capability of the structure and introducing the class.

This lesson culminates with the presentation and explanation of an object-oriented Stack class.

Combining Data Into Structures

A structure bundles together a set of data values of different types. For example, information about an employee could be stored in the structure shown in Figure 1.

Figure 1. A structure containing employee information.
  struct employee {
    char last_name[30];
    char first_name[20];
    double employee_no;
      .
      .
      .
    float annual_salary;
  };

In C++, the code shown in Figure 1 defines a new data type named employee and specifies the list of data items (members) that a variable of type employee will have.

Using Parts of a Structure

Accessing fields of a structure
A field or member of a structure is referred to by using the structure name followed by a period and the member name.

The example program shown in Listing 1 bundles together some of the information that a program would need to keep track of information about planets.  Given the explanation in the sidebar, the expression mars.distance in Listing 1 is a reference to the structure's member containing the distance of Mars from the Sun in astronomical units.

Accessing fields of a structure
A field or member of a structure is referred to by using the structure name followed by a period and the member name.

Listing 1. Source code for the program named Prog125B.
//File Prog125B
/*********************************************************
This program bundles together some of the information that
a program would need to keep track of information about
planets.
*********************************************************/
#include <iostream>
using namespace std;
#include <string>

struct planet{
  char name[10];
  float distance;
  float radius;
};

planet mars;

int main(){
  strcpy(mars.name,"Mars");
  mars.distance = 1.5;
  mars.radius = 0.4;

  cout << "Planetary statistics:\n";
  cout << "Name: "<< mars.name << '\n';
  cout << "Distance from Sun in AU: "
                                 << mars.distance << '\n';
  cout <<"Radius in Earth radii: " << mars.radius << '\n';

  //return 0;
  //Following statements cause Dev-C++ output to remain
  // on the screen
  system("PAUSE");
  return EXIT_SUCCESS;
}//end main

A template for a new data type

Listing 1 begins by using the struct keyword to create a template for a new data type named planet.  Then it creates a variable of type planet named mars.  The variable named mars is manipulated in the main function.

The struct keyword gives the name planet to a structure consisting of three members or fields. The name field is an array of characters, while the distance and radius fields are floating-point values.

The strcpy function
The library function named strcpy can be used to copy a string value into a structure field that holds an array of characters.
 

Declare a variable

The declaration

planet mars
in Listing 1 creates a variable named mars whose type is planet.

Populate the members

Values are assigned to the three data members (fields) by code in the main function.  Then the values stored in the three data members are displayed.

Notation for accessing data members

The following notation

name.member
is used in Listing 1 to reference the individual data members of the structure for the purpose of storing as well as retrieving the values stored in those data members.

The screen output

Figure 2 shows the program output that appears on the command-line screen.

Figure 2. Output from program named Prog125B.
Planetary statistics:
Name: Mars
Distance from Sun in AU: 1.5
Radius in Earth radii: 0.4
Press any key to continue . . .

Three Properties of an Object-Oriented Programming Language

As I mentioned earlier, this lesson begins the transition from procedural programming to object-oriented programming (OOP).  This lesson also begins the introduction of important concepts that make C++ useful for object-oriented programming.

Models of the real world

OOP is a method of programming that seeks to mimic the way we form models of the real world. To cope with the complexities of life, we have evolved a capacity to generalize, classify, and generate abstractions. Many nouns in our vocabulary represent a class of objects sharing some set of attributes or behavioral traits. For example, from a world full of individual plants, we derive the abstract classes called fruit and vegetable. This allows us to develop and process ideas about fruits and vegetables without being distracted by the details concerning any fruit or vegetable. The OOP extensions in C++ exploit this natural tendency we have to classify and abstract things.

In addition to abstraction, an OOP program is characterized by three main characteristics:

This lesson will deal with encapsulation and defer inheritance and polymorphism until later in the series.

Encapsulation

The word encapsulation derives from the word capsule.  Most of us are familiar with capsules in a medical sense where a capsule is a container that contains medicine.

Encapsulation in C++ combines data and the functions used to manipulate that data in a single class-type object. For example, you might develop a data structure, such as an array holding the information needed to draw a character font on the screen, and the code (functions) for displaying, scaling, rotating, highlighting, and coloring your font character.

Different from procedural programming

In procedural programming, a common approach might be to put the data structures and related functions into a single, separately compiled source file in an attempt to treat code and data as a single module. While this is a step in the right direction, it isn't good enough. There is no explicit relationship between the data and the code, and you or another programmer can still access the data directly without using the functions provided. This can lead to problems.

For example, suppose that you decide to replace the array of font information with a linked list? Another programmer working on the same project may decide that he has a better way to access the font data, so he writes some functions of his own that manipulates the array directly. The problem is that the array isn't there any more after you replace the array with a linked list, so problems will ensue. You need a way to ensure that the data can be accessed only by calling functions that you provide.

C++ provides the class keyword

C++ extends the power of C's struct and union keywords by adding a keyword not found in C: class. Note that we must be careful to distinguish between class or classes as a concept, and class as a keyword. All three keywords are used in C++ to define classes in general. However, many C++ programmers prefer to use the keyword class to define a class and to use the keyword struct in its more conventional sense.

Defining and instantiating a new type

In C++, a single class entity (defined with the keywords struct, union, or class) combines functions (known as member functions) and data (known as data members). You usually give a class a useful name, such as Font. This name becomes a new type identifier that you can use to declare instances or objects of that class type.   See the code fragment in Figure 3, for example, which shows the C++ syntax for defining a new type using the class keyword and declaring an object of the new type.

Figure 3. Code fragment for a Font class.
  class Font{
  //Declare your members here:  both data and functions;
  //Don't worry about how for the moment.
  };//note the semicolon
  
  //Declares variable fancyFontVar to be of type Font
  Font fancyFontVar;

The variable fancyFontVar is an instance (sometimes called an instantiation) of the class Font. The variable fancyFontVar is also an object.

Using the new object

You can use the class name Font very much like a normal C data type. For example, you can declare arrays and pointers as shown in Figure 4.

Figure 4. Declaring arrays and pointers of a class type.
  Font anArray[10];//declare an array of 10 Font objects
  Font* font_ptr;  //declare a pointer of type Font

Differences between class, struct, union etc.

A major difference between C++ classes and C structures concerns the accessibility of members. The members of a C structure are freely available to any expression or function within their scope and there is nothing that you can do to protect those members from unauthorized access.

A C++ union
According to MSDN, a C++ union is a limited form of the class type. It can contain access specifiers (public, protected, private), member data, and member functions, including constructors and destructors. It cannot contain virtual functions or static data members. It cannot be used as a base class, nor can it have base classes. Default access of members in a union is public.

The members of a C++ structure are also, by default, freely available to any expression or function within their scope.  However, with C++, you can control access to struct and class members (code and data) by declaring individual members as public, private, or protected.  These three access levels will be explained in more detail later on.

Three keywords for defining classes

C++ structures and unions offer more than their C counterparts.  They can hold function declarations and definitions as well as data members. In C++, the keywords struct, union, and class can all be used to define classes.

So, when we talk about classes in C++, we include structures and unions, as well at types defined by the keyword class.  However, in this series of tutorials, I will probably concentrate mostly on classes declared using the keyword class and leave struct and union for others to discuss.

Good programming practice

Typically in OOP, you restrict data member access to member functions only.  You usually make the data members private and the member functions that access those data members public.

Back to the Font class

Returning to the hypothetical problem of handling fonts (see Figure 3), how does the C++ class concept help? By creating a suitable Font class, you can ensure that the private font data members can be accessed and manipulated only through the public Font member functions that you have created for that purpose.

Free to change the implementation

You are then free at any time to change the font data structure from an array to a linked list, or whatever. You would, of course, need to re-code the member functions to handle the new font data structure, but if the function names and arguments are unchanged, programs (and programmers) in other parts of your system will be unaffected by your improvements.

Equal and interdependent partners

Thus, the technique of encapsulation in classes helps provide the very real benefit of modularity. The C++ class establishes a well-defined interface that helps you design, implement, maintain, and reuse programs. The class concept leads to the idea of data abstraction. Our font data structure is no longer tied to any particular physical implementation; rather, it is defined in terms of the operations (member functions) allowed on it. The C++ class combines data and function as equal, interdependent partners.

Specifics

The class is the mechanism that is used to create objects. As such, the class is at the heart of many C++ features. The syntax of a class declaration using the keyword class is shown in Figure 5.

Figure 5. Syntax of a class declaration.
  class class-name{
    private functions and variables of the class
  public:
    public functions and variables of the class
  } optional object-list;

An optional object list

Note that the object list in the class declaration is optional. You can declare class objects later, as needed.  (Even if you omit the object list, however, you must include the semicolon.)

An optional class name

While the class-name is also technically optional, from a practical point of view, it is almost always needed. The reason for this is that the class-name becomes a new type name that is used to declare objects of the class.

Members of the class

Functions and variables declared inside a class declaration are said to be members of that class. By default, all functions and variables declared inside a class are private to that class (where the word class in this context means class and not struct, or union). This means that they are accessible only by other members of that class. The public keyword is used followed by a colon to declare public class members.  All functions and variables declared after the public keyword are accessible both by other members of the class and by any other part of the program that contains or has access to the class.

A simple class declaration

Listing 2 shows a simple class declaration using the class keyword without the optional object list.

Listing 2. A simple class declaration.
  class MyClass{
    int data;//private to MyClass
  public:
    void setData(int num);
    int getData();
  };//note the required semicolon

Function prototype
A function prototype in C or C++ is a declaration of a function that omits the function body but does specify the function's name, arity, argument types and return type. While a function definition specifies what a function does, a function prototype can be thought of as specifying its interface.

In a prototype, argument names are optional, however, the type is necessary along with all modifiers (i.e. if it is a pointer or a const argument).

This class has one private variable (data member), named data and two public member functions named setData and getData.

Note that functions are declared within a class using their prototype forms. (A complete definition of each prototype function must be provided elsewhere.)  Functions that are declared to be part of a class are called member functions.

Access control

The variable named data is private.  Therefore, it is not accessible by any code outside MyClass. However, because the two member functions are members of the class, they have direct access to data. The two member functions are declared as public members of the class.  Therefore, they can be called by any other part of the program that contains or has access to the class.

Defining a member function

Although the two member functions are declared by the class in Listing 2, they are not yet defined. To define a member function, you must link the name of the class to which the member function belongs with the name of the function. You do this by preceding the function name with the class name and separating the two by two colons. The two colons are called the scope resolution operator. Listing 3 shows how the two member functions might be defined outside of the class declaration.

Listing 3. Syntax for defining member functions.
  void MyClass::setData(int num){//note the two colons
    data = num;
  } // end setData

  int MyClass::getData(){
    return data;
  }//end getData

Because the two functions are member functions of the class, they have direct access to the private variable named data.

When you define a member function, use the general form shown in Figure 6 (unless it is defined as an inline function which will be explained later).

Figure 6. General syntax for defining a member function.
  type class_name::func-name(parameter-list){
    ... // body of function
  }//end of function

Instantiating an object of the class

The declaration of MyClass in Listing 2 did not define any objects of type MyClass.  The declaration and the associated function definitions simply defined the type of object that will be created when an object of the class is actually declared (instantiated). To instantiate an object, use the class name to specify the type. For example, the statement in Listing 4 declares (instantiates) two objects of type MyClass.

Listing 4. Declare two objects of type MyClass.
MyClass obj1, obj2;  

Class versus object
A class declaration is a logical abstraction that defines a new type.  The new type determines what an object of that type will look like. An object declaration creates a physical entity of that type.

Accessing public members of an object

Once an object of a class has been instantiated, the program can reference its public members by using the dot (period) operator in conjunction with the name of the object.

For example, the code in Listing 5 calls the setData function belonging to objects obj11 and obj2 passing an int value as a parameter each time the function is called.  Referring back to the definition of the setData method in Listing 3, we see that this causes the parameter value to be stored in the private variable named data belonging to the object on which the function is called.

Listing 5. Calling the setData method to store data in objects.
obj1.setData(10);// sets ob1's version of data to 10
obj2.setData(20);// sets ob2's version of data to 20

Instance variables
The non-static data members of a class are often called instance variables because every instance of the class (object) has one.  Static variables are often called class variables because all objects instantiated from the class (if any) share a single copy.

Instance variables

Each object contains its own copy of all data members declared in the class (except for the special case where the data member is declared as static, which will be discussed later). This means that the copy of data belonging to obj1 is distinct and different from the copy belonging to obj2.

Example Program for MyClass

Putting everything discussed so far into context, the sample program shown in Listing 6 uses MyClass described earlier to set the value of data for obj1 and obj2 and to display the value of data for each object.

Listing 6. Source code for the program named Prog125A.
//File Prog125A
/*********************************************************
This program declares a class named MyClass, defines 
functions for entering data into and getting data from a 
private variable named data, creates two instances of the 
class (objects), and manipulates those objects.
*********************************************************/

#include <iostream>
using namespace std;

class MyClass{
  int data;//variable is private by default
public://everything following this is public
  //The following are function prototypes.
  //Public function to put a value into the variable data
  void setData(int num);
  //Public function used to get value stored in data
  int getData();
};//end of class declaration
//------------------------------------------------------//

//The following are function definitions.
void MyClass::setData(int num){
  data = num;
}//end definition of setData function

int MyClass::getData(){
  return data;
}//end definition of getData function

int main(){
  //declare two instances (objects) of the class
  MyClass obj1, obj2;

  //Store different values in each object.t.
  obj1.setData(10);
  obj2.setData(20);

  //Get and display the value stored in each object.
  cout << obj1.getData() << "\n";
  cout << obj2.getData() << "\n";

  //return 0;
  //Following statements cause Dev-C++ output to remain
  // on the screen
  system("PAUSE");
  return EXIT_SUCCESS;
}//end main

You should be able to copy, compile, and execute the program shown in Listing 6 using Dev-C++.  When you do, the values 10 and 20 should be displayed on separate lines on the command-line screen.  If you want to use a tool other than Dev-C++, modify the statements at the end of the main method accordingly.

Public Member Variables

A class declaration can contain public member functions and can also contain public member variables. For example, the member variable named data could be accessed from any part of the program if the class were declared as shown in Listing 7.

Listing 7. Class with public member variable.
class MyClass {
public:
  int data;//variable is public to this class
  //Function to enter a value into the variable data
  void setData(int num);
  //Function used to access the value of the variable data
  int getData();
};//end of class declaration

Poor programming style
Good object-oriented programming style normally discourages the use of public member variables unless they are also constants.

In this case, there would be no need for the two member functions since their purpose is to provide an interface to the member variable data. Note however, that you would need to use the dot operator (obj1.data) to access the member variable.

Stack Class Example Program

It's time to get a real taste of the power of objects.  For that, we will examine a more practical example. The program in Listing 18 creates a class named Stack that implements a stack that can be used to store and retrieve characters in a "last-in, first-out" (LIFO) fashion.

I will explain this program in fragments.  Before getting into those details, however, I will present the screen output from the program shown in Figure 7 for reference later.

Figure 7. Screen output from the Stack program.
StackA is full
StackB is full
Pop stackA: c
Pop stackB: C
Pop stackA: b
Pop stackB: B
Pop stackA: a
Pop stackB: A
StackA is empty
StackB is empty
Press any key to continue . . .

A LIFO stack capability

This program creates a Stack class that provides a LIFO
(Last In First Out) stack capability.  If you are unfamiliar with a LIFO container, it is essentially a container for data that lets you put data in, and then take the data back out later in a specific order.  When you remove a piece of data from the stack, it will be the one most recently put into the container.

I have seen an analogy that compares a stack to the spring-loaded container that holds trays in some cafeterias.  A cafeteria employee places clean trays in the container at the top.  Customers remove trays from the top.  When a customer removes a tray, it is the tray that was most recently put into the container by the cafeteria employee.  If the cafeteria never runs out of clean trays, the first tray that was put in will remain at the bottom of the stack of trays forever and will never be used by a customer.

Two objects of a Stack class

In this program, two objects of the Stack class are instantiated and manipulated.  This is a good example of OOP where the stacks are objects that can be manipulated by the program.

Compiler directives

The program begins in Listing 8 with the requisite compiler directives plus a directive to set the value of a constant named SIZE to 3.  This constant will be used to specify the number of data values that can be stored in the stack before it overflows.

Listing 8. Compiler directives.
#include 
using namespace std;
#define SIZE 3 //used to control the size of the stack

Declare a Stack class for storing char data

Listing 9 declares a class named Stack and declares two instance variables in the class.  The instance variable named myStack is an array that will be used to store and retrieve the actual data that will be stored and retrieved from the stack.  The instance variable named index will be used to keep track of the data inside the stack.

Listing 9. Declare a Stack class for storing char data.
class Stack{
  //Create a char array to serve as the stack
  char myStack[SIZE];
  //Create a variable to index within the stack
  int index;

The instance variables that are declared in Listing 9 are private by default.

Declare three functions

Listing 10 provides the public prototypes of three functions that will be defined later outside the class declaration.

Listing 10. Declare three functions.
public:
  void init();
  
  int push(char ch);
  
  char pop();
};//end of class declaration

The function named init will be used to initialize an object instantiated from the Stack class.

The function named push will be used to store a value of type char in the stack.  Note that push is a commonly used name for functions that perform this operation.

The function named pop will be used to remove a value from the stack.  Also note that pop is a commonly used name for functions that perform this operation.

Listing 10 also signals the end of the class declaration.

Define the function used to initialize the stack

Listing 11 defines the function that is used to initialize the stack.  Note the use of the scope resolution operator to associate this function definition with the function declaration provided in Listing 10.

Listing 11. Define the function used to initialize the stack.
void Stack::init(){
  index = 0;//set the index to zero
}//end init function

The code in Listing 11 is straightforward and shouldn't require an explanation.

Define the function to push a character onto the stack

Listing 12 provides the definition for the push function declaration in Listing 10.

Listing 12. Define the function to push a character onto the stack.
int Stack::push(char ch){
  if(index==SIZE){
    return -1;//full
  }else{
    myStack[index] = ch;//store indexed into the array
    index++;//increment the index
    return 0;
  }//end else
}// end definition of push()

The push method must prevent an actual stack overflow if the using program attempts to store data in excess of the capacity of the stack.  If that happens, the code in Listing 12 simply refuses to store the data value and returns a value of negative 1 as a flag to the using program that a stack overflow error has occurred.

A private instance variable
The private instance variable named index is accessible by the function named push because push is a non-static member of the class.

Otherwise, the new data value is stored in the array at the location specified by the current value of the private instance variable named index.  Then the value of index is incremented so that the storage location of the next value will not be the same as the storage location of the current value.

Finally, the method returns a value of 0 to indicate that the storage of the value in the stack was successful.

Define the function to pop a character off the stack

Listing 13 defines the function that is used to remove a character from the stack.

Listing 13. Define the function to pop a character off the stack.
char Stack::pop(){
  if(index == 0){
    return -1;//empty
  }else{
    index--;//decrement the index
    //Access the array and return the character
    return myStack[index];
  }//end else
}//end definition of pop()

The pop function must deal with the possibility that the using program will attempt to remove a value from an empty stack.  If this happens, the function simply returns a value of negative 1 to indicate that the stack is empty and the attempt was unsuccessful.

Otherwise, Listing 13 decrements the value of index to cause it to point to the location of the value that was most recently stored in the array.  It uses the new value of index to access and return that value.

Removal from an array is not possible

It is not possible to physically remove a value from a C++ array, so the code in Listing 13 doesn't actually remove the value from the array.  However, referring back to Listing 12, we see that the next call to the push function will cause the new value to be stored in the array location from which the value was retrieved in Listing 13, effectively replacing the old value by a new value.

Listing 13 also represents the end of the class definition for the class named Stack.  At this point, all three of the function prototypes that were declared in Listing 10 have been defined.

Beginning of the main function

Listing 14 shows the beginning of the main function.  The main function is designed to test the Stack class by creating and manipulating two objects of the class.

Listing 14. Beginning of the main function.
int main(){
  Stack stackA, stackB;//create two objects of class Stack
  
  //Initialize the two stacks
  stackA.init();
  stackB.init();

Listing 14 begins by declaring two variables of the Stack class named stackA and stackB.  This instantiates two objects of the Stack class and makes them accessible via the names of the variables.

Then the code in Listing 14 uses the variable name in conjunction with the dot operator to call the init method on each object to initialize them.

Push data onto the two Stack objects

Listing 15 uses the variable names and the dot operator to call the push method several times in succession to push some data onto each of the two stacks. An attempt is made to overflow both stacks in order to test the capability of each object to prevent a physical overflow.

Listing 15. Push data onto the two Stack objects.
  for(int cntr = 0;cntr < SIZE + 1;cntr++){
    if(stackA.push('a' + cntr) == -1){
      cout << "StackA is full\n";
    }//end if
    if(stackB.push('A' + cntr) == -1){
      cout << "StackB is full\n";
    }//end if
  }//end for loop

The code in Listing 15 causes the first two lines of text shown in Figure 7 to be displayed on the screen.  These two lines of text are produced when the attempt is made to overflow each of the stacks.

Once the code in Listing 15 has finished execution, three characters have been stored in each stack and one character has been rejected for each stack.

Pop data values off of each stack

Listing 16 pops all of the data off of each stack and purposely attempts to pop more data than is currently stored in each stack.

Listing 16. Pop data values off of each stack.
  for(int cnt=0;cnt < SIZE + 1;cnt++){
    char data = stackA.pop();
    if(data == -1){
      cout << "StackA is empty\n";
    }else{
      cout << "Pop stackA: " << data << "\n";
    }//end else
    
    data = stackB.pop();
    if(data == -1){
      cout << "StackB is empty\n";
    }else{
      cout << "Pop stackB: " << data << "\n";
    }//end else
  }//end for loop

Each value is displayed as it is popped as shown in Figure 7.  When all of the data in the stack has been popped and another attempt is made to pop a value, the pop method returns a value of negative 1 causing the empty messages shown in Figure 7 to be displayed.

End of the main function

Listing 17 shows the end of the main function and the end of the program.

Listing 17. End of the main function.
  //return 0;
  //Following statements cause Dev-C++ output to remain
  // on the screen
  system("PAUSE");
  return EXIT_SUCCESS;
}//end main

Listing 17 includes the two statements that are required to cause the Dev-C++ output to remain on the command-line screen so that you can view it.  If you run this program with some other C++ tool, you may need to delete these two statements and re-enable the standard return statement shown in Listing 17.

Summary

This lesson introduced you to the C++ extensions to the structure and the union.  It also introduced you to the class keyword and the C++ capability embodied in the class.

As a capstone, the lesson presented and explained an object-oriented Stack class.

Complete program listings

Complete listings of the programs discussed in this lesson are either included in the above text, or are shown below.

Listing 18. Source code for the Stack program.
//File Prog125C.cpp 08/01/08
/*********************************************************
This example creates a Stack class that provides a LIFO
(Last In First Out) stack capability.  Two objects of the
Stack class are instantiated and manipulated.  This is a
good example of OOP where the stacks are objects that can
be manipulated by the program.
*********************************************************/

#include <iostream>
using namespace std;
#define SIZE 3 //used to control the size of the stack

//Declare a Stack class for storing char data
class Stack{
  //Create a char array to serve as the stack
  char myStack[SIZE];
  //Create a variable to index within the stack
  int index;
public:
  void init();//function to initialize the stack
  
  //Function to push characters onto the stack
  int push(char ch);
  
  char pop();//function to pop characters off the stack
};//end of class declaration
//------------------------------------------------------//

//Define the function used to initialize the stack
void Stack::init(){
  index = 0;//set the index to zero
}//end init function

//Define the function to push a character onto the stack
int Stack::push(char ch){
  if(index==SIZE) {
    return -1;//full
  }else{
    myStack[index] = ch;//store indexed into the array
    index++;//increment the index
    return 0;
  }//end else
}// end definition of push()

//Define the function to pop a character off the stack
char Stack::pop(){
  if(index == 0){
    return -1;//empty
  }else{
    index--;//decrement the index
    //Access the array and return the character
    return myStack[index];
  }//end else
}//end definition of pop()
//------------------------------------------------------//

//Test the program by creating and manipulating two
// objects of class Stack
int main(){
  Stack stackA, stackB;//create two objects of class Stack
  //Initialize the two stacks
  stackA.init();
  stackB.init();

  //Push some data onto the two stacks. Purposely try to
  // overflow both stacks.
  for(int cntr = 0;cntr < SIZE + 1;cntr++){
    if(stackA.push('a' + cntr) == -1){
      cout << "StackA is full\n";
    }//end if
    if(stackB.push('A' + cntr) == -1){
      cout << "StackB is full\n";
    }//end if
  }//end for loop
  
  // Now pop the values off the two stacks. Purposely
  // attempt to pop more data than exists in the stacks.
  for(int cnt=0;cnt < SIZE + 1;cnt++){
    char data = stackA.pop();
    if(data == -1){
      cout << "StackA is empty\n";
    }else{
      cout << "Pop stackA: " << data << "\n";
    }//end else
    
    data = stackB.pop();
    if(data == -1){
      cout << "StackB is empty\n";
    }else{
      cout << "Pop stackB: " << data << "\n";
    }//end else
  }//end for loop

  //return 0;
  //Following statements cause Dev-C++ output to remain
  // on the screen
  system("PAUSE");
  return EXIT_SUCCESS;
}//end main


Copyright

Copyright 2008, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP).  His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments.  (TI is still a world leader in DSP.)  In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com

-end-