Click Here!
home account info subscribe login search FAQ/help site map contact us


 
Brief Full
 Advanced
      Search
 Search Tips
[an error occurred while processing this directive]
Previous Table of Contents Next


4.  Save CALLCHAIN.CPP. Create a new file named MAIN.CPP under the same project of CALLCHAIN.H and type the following code into that file:
#include “callchain.h”

void main()
{
 status stat = success;
 CallChain chain;

 stat = chain.Call(“func1”); //push first function after main
 if (stat != failure) //then call another one
 {
  stat = chain.Call(“bad_func”); // call the offending function,
				 // which throws an exception
 }
 if (stat != success)
 {
  chain.Throw(“disaster!”); //unwind stack
 }

}//end main
5.  Save MAIN.CPP and compile your project.
If your compiler complains about the following #include statements in CALLCHAIN.H or CALLCHAIN.CPP:
#include <stack>
#include <string>
#include <iostream>

comment out (or remove) the using directive just below these #include statements and change them to read:
#include <stack.h>
#include <string.h>
#include <iostream.h>
6.  Compile and link the project.
7.  Run main.exe; the output should be as follows:
pushed main; total: 1
pushed func1; total: 2
pushed bad_func; total 3
popped bad_func; total 2
popped func1; total 1
popped main; total 0

How It Works

Let us begin by examining the header file CALLCHAIN.H.

The first source line includes the definition of the class string. The second line includes the definition of the STL stack container. The following using directive instructs the compiler to resolve all references to namespace std.

In the following source line

enum status { success, failure };

an enum type named status is defined. It is used to return a success or failure code from the member functions defined in CallChain class. Class CallChain itself is declared in the following source line. This class is used to simulate a simplified mechanism of a function call chain.

class CallChain {

Next, declare the first class member named st as a private member:

stack <string> st;

st is an object of type stack <string>. st holds string elements. A string object is sued to denote a function. That is, the entities are the names of the functions. You could have chosen a different method to represent a function, say a pointer, or a class. However, string is a simple and clear representation for the purposes of this How-To.

Next, declare two protected member functions:

protected:
  bool CallChain::HandlerExists(const string& excep);
  void ExitCurrentScope();

The first member function is used to examine whether a handler for the current exception exists in the current scope. In this case, the member function is a stub, which always returns false. The second member function performs a forced exit from the current scope. In other words, it pops the current function from the stack. These member functions are declared protected because they are more of helper functions used by other members of the class; they are not supposed to be invoked directly.

The interface of a class consists of its public members. CallChain’s interface is specified in the following source lines.

First, declare a constructor:

CallChain();

A destructor comes next:

~CallChain();

The Call member function simulates a function call, which is in fact a push operation performed on the stack.

status Call(const string& function);

Finally, the member function Throw performs a complete stack unwinding; it performs iterative push operations until the stack is empty. This is equivalent to throwing an exception that has no handler—the program is aborted.

void Throw(const string& excep);

Now you have a basic idea of how the exception handling mechanism works, and how it relates to the stack data model. Let’s take a look at CALLCHAIN.CPP. This file contains the implementation of the CallChain class. First, include the <iostream> header. The next header file is callchain.h, which contains the declaration of the class CallChain, as you just saw. A using directive is necessary for the compiler to resolve accurately the names of <iostream>.

Let’s examine the constructor of CallChain:

CallChain::CallChain()
{
  st.push(“main”);
  cout<<”pushed main; total “<<st.size()<<endl;
}

The first statement in the constructor performs a push operation. That is, it pushes an element onto our stack. It pushes an argument of type string, which is the expected type for the specialization stack<string> you used. As in a vector, every push operation applied to a stack inserts a new member into a position higher than the previous one. In this case, the constructor pushes the first element onto the st. Thus, a CallChain object begins its life with a stack that has one element—main.

The destructor performs the opposite action; that is, it pops the stack, unless it is already empty. Remember that popping an empty stack is an error, so stack::empty() is called first to check whether the stack is empty.

CallChain::~CallChain()
{
  if (!st.empty() )
    st.pop();
}

The member function Call calls a function. It receives the function name as its argument, and pushes it on the stack.

status CallChain::Call(const string& function)
{
  st.push(function);
  cout<<”pushed “ <<function<< “; total: “<< st.size() <<endl;
  if (function == “bad_func”)
    return failure;
  return success;
}

However, one of the functions called is an offender—it throws an exception for which no handler exists. This function is identified by its name: bad_func. The Call member function checks whether the function it has just pushed is the offending function by comparing the function’s name. If this function throws an exception, Call returns a failure value, which indicates that an exception has occurred.


Previous Table of Contents Next


Products |  Contact Us |  About Us |  Privacy  |  Ad Info  |  Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-1999 EarthWeb Inc.
All rights reserved. Reproduction whole or in part in any form or medium without express written permision of EarthWeb is prohibited.