Exceptions are an integral and unavoidable part of the operating system and programming. One way you can handle them is to create classes whose behaviors are prepared to deal with abnormal behavior. There are two main ways you can involve classes with exception handling routines: classes that are involved in exceptions of their own operations and classes that are specially written to handle exceptions for other classes. |
Transferring Exceptions to Classes |
|
You can create a class that is not specifically oriented towards exceptions, as any of the classes we have used so far. The simplest way to take care of exceptions in classes is to use any normal class and handle its exceptions. Such a class appears like one of the classes we have used already, except that exceptions of its abnormal behavior are taken care of.
If concerned with exceptions, the minimum thing you can do in your program
is to make it "aware' of eventual exceptions. This can be taken care
of by including transactions or other valuable processing in a try block,
followed by a three-dot catch as in catch(...). The catch in this case is
prepared to handle any exception that could occur. Here is an example of a
simple class: |
|
//---------------------------------------------------------------------------
#include <iostream>
#include <iomanip>
#include <conio>
using namespace std;
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
const double PriceShirt = 0.99;
const double PricePants = 1.75;
struct TCleaningOrder
{
int NumberOfShirts;
int NumberOfPants;
int NumberOfMisc;
};
int main(int argc, char* argv[])
{
TCleaningOrder Order;
double TotalPriceShirts, TotalPricePants;
double PriceMisc, TotalPriceMisc;
double TotalOrder;
cout << " - Georgetown Cleaning Services -\n";
cout << " - Customer Order Processing -\n";
try {
cout << "Number of\n";
cout << "Shirts: ";
cin >> Order.NumberOfShirts;
cout << "Pairs of Paints: ";
cin >> Order.NumberOfPants;
cout << "Misc. Items(if none, type 0): ";
cin >> Order.NumberMisc;
// If there are miscalleanous items,...
if(Order.NumberOfMisc > 0)
{
// let the user determine the price of this misc item
cout << "Enter the price of each miscellanous item: ";
cin >> PriceMisc;
TotalPriceMisc = Order.NumberOfMisc * PriceMisc;
}
else
TotalPriceMisc = 0.00;
TotalPriceShirts = Order.NumberOfShirts * PriceShirt;
TotalPricePants = Order.NumberOfPants * PricePants;
TotalOrder = TotalPriceShirts + TotalPricePants + TotalPriceMisc;
clrscr();
cout << setiosflags(ios::fixed) << setprecision(2);
cout << " - Georgetown Cleaning Services -";
cout << "\n - Customer Receipt -";
cout << "\n============================";
cout << "\n Item\tNumber\tPrice";
cout << "\n----------------------------";
cout << "\n Shirts\t" << Order.NumberOfShirts
<< "\t$" << TotalPriceShirts;
cout << "\n Pants\t" << Order.NumberOfPants
<< "\t$" << TotalPricePants;
cout << "\n Misc\t" << Order.NumberOfMisc
<< "\t$" << TotalPriceMisc;
cout << "\n============================";
cout << "\n Total Order:\t$" << TotalOrder;
}
catch(...)
{
cout << "\nSomething went wrong - Too Bad";
}
cout << "\n\nPress any key to continue...";
getch();
return 0;
}
//---------------------------------------------------------------------------
|
Nevertheless, we have learned so far to catch
exceptions and to throw them to a section that can handle them. One of the
problems that could occur in a program is the clerk not entering valid
numbers, which would imply that we want the compiler to multiply strings
by constant numbers. Therefore, we can examine each number that the clerk
would type and handle its exception in case of an invalid number.
The simplest way you can check an integer is through
the use of the isdigit() function. The only problem we will have at this
time is that the isdigit() function checks only one digit or character.
Here is one attempt at addressing the problem: |
|
//---------------------------------------------------------------------------
#include <iostream>
#include <iomanip>
#include <conio>
using namespace std;
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
// Constant prices of items, set by the store management
const double PriceShirt = 0.99;
const double PricePants = 1.75;
// Create an order object
struct TCleaningOrder
{
int NumberOfShirts;
int NumberOfPants;
int NumberOfMisc;
};
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TCleaningOrder Order;
double TotalPriceShirts, TotalPricePants;
double PriceMisc, TotalPriceMisc;
double TotalOrder;
cout << " - Georgetown Cleaning Services -\n";
cout << " - Customer Order Processing -\n";
try {
cout << "Number of\n";
cout << "Shirts: ";
cin >> Order.NumberOfShirts;
if( isdigit(Order.NumberOfShirts) )
throw Order.NumberOfShirts;
cout << "Pairs of Paints: ";
cin >> Order.NumberOfPants;
if( isdigit(Order.NumberOfPants) )
throw Order.NumberOfPants;
cout << "Misc. Items(if none, type 0): ";
cin >> Order.NumberMisc;
if( isdigit(Order.NumberOfMisc) )
throw Order.NumberOfMisc;
// If there are miscalleanous items,...
if(Order.NumberMisc > 0)
{
// let the user determine the price of this misc item
cout << "Enter the price of each miscellanous item: ";
cin >> PriceMisc;
TotalPriceMisc = Order.NumberOfMisc * PriceMisc;
}
else
TotalPriceMisc = 0.00;
TotalPriceShirts = Order.NumberOfShirts * PriceShirt;
TotalPricePants = Order.NumberOfPants * PricePants;
TotalOrder = TotalPriceShirts + TotalPricePants + TotalPriceMisc;
clrscr();
cout << setiosflags(ios::fixed) << setprecision(2);
cout << " - Georgetown Cleaning Services -";
cout << "\n - Customer Receipt -";
cout << "\n============================";
cout << "\n Item\tNumber\tPrice";
cout << "\n----------------------------";
cout << "\n Shirts\t" << Order.NumberOfShirts
<< "\t$" << TotalPriceShirts;
cout << "\n Pants\t" << Order.NumberOfPants
<< "\t$" << TotalPricePants;
cout << "\n Misc\t" << Order.NumberMisc
<< "\t$" << TotalPriceMisc;
cout << "\n============================";
cout << "\n Total Order:\t$" << TotalOrder;
}
catch(const int n)
{
cout << n << " is not a valid number";
}
catch(...)
{
cout << "\nSomething went wrong - Too Bad";
}
cout << "\n\nPress any key to continue...";
getch();
return 0;
}
//---------------------------------------------------------------------------
|
Practical Learning: Introduction to Class' Exceptions |
|
- Start Borland C++ Builder and create a C++ Console Application using
the Console Wizard.
- Click the Save All button on the Standard toolbar.
- Create a folder called Exceptional1 and display it in the Save In
combo box.
- Save the unit as Main and save the project as Exceptional
- Change the content of the Main.cpp file as follows:
//---------------------------------------------------------------------------
#include <iostream>
#include <conio>
using namespace std;
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
class TCalculator
{
public:
double Operand1;
double Operand2;
char Operator;
};
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TCalculator Calc;
double Result;
// Request two numbers from the user
cout << "This program allows you to perform an operation on two numbers\n";
cout << "To proceed, enter two numbers\n";
try {
cout << "First Number: ";
cin >> Calc.Operand1;
cout << "Operator: ";
cin >> Calc.Operator;
cout << "Second Number: ";
cin >> Calc.Operand2;
// Make sure the user typed a valid operator
if(Calc.Operator != '+' && Calc.Operator != '-' &&
Calc.Operator != '*' && Calc.Operator != '/')
throw Calc.Operator;
// Find out if the denominator is 0
if(Calc.Operator == '/')
if(Calc.Operand2 == 0)
throw 0;
// Perform an operation based on the user's choice
switch(Calc.Operator)
{
case '+':
Result = Calc.Operand1 + Calc.Operand2;
break;
case '-':
Result = Calc.Operand1 - Calc.Operand2;
break;
case '*':
Result = Calc.Operand1 * Calc.Operand2;
break;
case '/':
Result = Calc.Operand1 / Calc.Operand2;
break;
}
// Display the result of the operation
cout << "\n" << Calc.Operand1 << " " << Calc.Operator << " "
<< Calc.Operand2 << " = " << Result;
}
catch(const char n)
{
cout << "\nOperation Error: " << n << " is not a valid operator";
}
catch(const int p)
{
cout << "\nBad Operation: Division by " << p << " not allowed";
}
cout << "\n\nPress any key to continue...";
getch();
return 0;
}
//---------------------------------------------------------------------------
|
- To test your program, on the main menu, click Run -> Run
- Test the program with two non-zero numbers. Here is an example:
This program allows you to perform an
operation on two numbers
To proceed, enter
First number: 1450
Second number: 32
1450 / 32 = 45.3125
Press any key to continue... |
- Return to Bcb
- You can also use external functions that check and throw exceptions to other functions that can handle
them. As an example, change the program as follows:
//---------------------------------------------------------------------------
#include <iostream>
#include <conio>
using namespace std;
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
class TCalculator
{
public:
double Operand1;
double Operand2;
char Operator;
};
//---------------------------------------------------------------------------
double __fastcall CalcResult(const double x, const char p, const double y)
{
double R;
// Perform an operation based on the user's choice
switch(p)
{
case '+':
R = x + y;
break;
case '-':
R = x - y;
break;
case '*':
R = x * y;
break;
case '/':
if( y == 0 )
throw 0;
R = x / y;
break;
}
return R;
}
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TCalculator Calc;
double Result;
// Request two numbers from the user
cout << "This program allows you to perform an operation of two numbers\n";
cout << "To proceed, enter two numbers\n";
try {
cout << "First Number: ";
cin >> Calc.Operand1;
cout << "Operator: ";
cin >> Calc.Operator;
cout << "Second Number: ";
cin >> Calc.Operand2;
// Make sure the user typed a valid operator
if(Calc.Operator != '+' && Calc.Operator != '-' &&
Calc.Operator != '*' && Calc.Operator != '/')
throw Calc.Operator;
Result = CalcResult(Calc.Operand1, Calc.Operator, Calc.Operand2);
// Display the result of the operation
cout << "\n" << Calc.Operand1 << " " << Calc.Operator << " "
<< Calc.Operand2 << " = " << Result << "\n\n";
}
catch(const char n)
{
cout << "\nOperation Error: " << n << " is not a valid operator";
}
catch(const int p)
{
cout << "\nBad Operation: Division by " << p << " not allowed";
}
cout << "\nPress any key to continue...";
getch();
return 0;
}
//---------------------------------------------------------------------------
|
- Test it and return to Bcb.
|
Introduction to Exceptions in Classes |
|
Probably the most basic use of exceptions you can make of
a class is to let a class handle its own exceptions and hand the result, reliable results, to
its clients. You handle exceptions in a class by using its method member. The main difference between a regular function and a class’ member function is that a regular function may need arguments from external functions to carry intermediary assignments. A member function of a class can use the member variables of the same class as if they were passed as arguments. You can use this
feature of classes to handle exceptions effectively. This allows each
class' method to handle its own exception(s), if any.
We saw earlier that when an order is being processed,
a clerk can enter an invalid number of items. Just like we did in the
main() function, we can take care of this possible exception in a function
where the order is being processed. Therefore, when solution to implement
for this type of scenario is to declare a function that processes orders
for the TCleaningOrder object. Here is an example: |
|
//---------------------------------------------------------------------------
#include <iostream>
#include <iomanip>
#include <conio>
using namespace std;
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
// Constant prices of items, set by the store management
const double PriceShirt = 0.99;
const double PricePants = 1.75;
// Create an order object
struct TCleaningOrder
{
public:
__fastcall TCleaningOrder();
__fastcall ~TCleaningOrder();
void __fastcall ProcessOrder();
void __fastcall DisplayReceipt();
private:
int NumberOfShirts;
int NumberOfPants;
int NumberOfMisc;
double TotalPriceShirts;
double TotalPricePants;
double TotalPriceMisc;
double TotalOrder;
};
//---------------------------------------------------------------------------
__fastcall TCleaningOrder::TCleaningOrder()
: NumberOfShirts(0), NumberOfPants(0), NumberMisc(0)
{
}
//---------------------------------------------------------------------------
__fastcall TCleaningOrder::~TCleaningOrder()
{
}
//---------------------------------------------------------------------------
void __fastcall TCleaningOrder::ProcessOrder()
{
double PriceMisc;
try {
cout << "Number of\n";
cout << "Shirts: ";
cin >> NumberOfShirts;
if( isdigit(NumberOfShirts) )
throw NumberOfShirts;
cout << "Pairs of Paints: ";
cin >> NumberOfPants;
if( isdigit(NumberOfPants) )
throw NumberOfPants;
cout << "Misc. Items(if none, type 0): ";
cin >> NumberMisc;
if( isdigit(NumberOfMisc) )
throw NumberOfMisc;
// If there are miscalleanous items,...
if(NumberMisc > 0)
{
// let the user determine the price of this misc item
cout << "Enter the price of each miscellanous item: ";
cin >> PriceMisc;
TotalPriceMisc = NumberOfMisc * PriceMisc;
}
else
TotalPriceMisc = 0.00;
TotalPriceShirts = NumberOfShirts * PriceShirt;
TotalPricePants = NumberOfPants * PricePants;
TotalOrder = TotalPriceShirts + TotalPricePants + TotalPriceMisc;
}
catch(const int n)
{
cout << n << " is not a valid number";
}
catch(...)
{
cout << "\nSomething went wrong - Too Bad";
}
}
//---------------------------------------------------------------------------
void __fastcall TCleaningOrder::DisplayReceipt()
{
cout << setiosflags(ios::fixed) << setprecision(2);
cout << " - Georgetown Cleaning Services -";
cout << "\n - Customer Receipt -";
cout << "\n============================";
cout << "\n Item\tNumber\tPrice";
cout << "\n----------------------------";
cout << "\n Shirts\t" << NumberOfShirts
<< "\t$" << TotalPriceShirts;
cout << "\n Pants\t" << NumberOfPants
<< "\t$" << TotalPricePants;
cout << "\n Misc\t" << NumberOfMisc
<< "\t$" << TotalPriceMisc;
cout << "\n============================";
cout << "\n Total Order:\t$" << TotalOrder;
}
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TCleaningOrder Order;
cout << " - Georgetown Cleaning Services -\n";
cout << " - Customer Order Processing -\n";
Order.ProcessOrder();
clrscr();
Order.DisplayReceipt();
cout << "\n\nPress any key to continue...";
getch();
return 0;
}
//---------------------------------------------------------------------------
|
Practical Learning: Class' Methods and their Exceptions |
|
-
As an example, change the program as follows:
//---------------------------------------------------------------------------
#include <iostream>
#include <conio>
using namespace std;
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
class TCalculator
{
public:
__fastcall TCalculator();
void __fastcall RequestOperands();
void __fastcall setOperation(const double x, const char p, const double y);
double __fastcall CalcResult() const;
void __fastcall DisplayResult() const;
private:
double Operand1;
double Operand2;
char Operator;
};
//---------------------------------------------------------------------------
__fastcall TCalculator::TCalculator()
{
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::RequestOperands()
{
try {
cout << "First number: ";
cin >> Operand1;
cout << "Operator: ";
cin >> Operator;
cout << "Second number: ";
cin >> Operand2;
// Make sure the user typed a valid operator
if(Operator != '+' && Operator != '-' &&
Operator != '*' && Operator != '/')
throw Operator;
setOperation(Operand1, Operator, Operand2);
}
catch(const char c)
{
cout << "Bad Operator: " << c << " is not a valid operator";
}
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::setOperation(const double Num,
const char c, const double Denom)
{
Operand1 = Num;
Operator = c;
Operand2 = Denom;
}
//---------------------------------------------------------------------------
double __fastcall TCalculator::CalcResult() const
{
double R;
// Perform an operation based on the user's choice
switch(Operator)
{
case '+':
R = Operand1 + Operand2;
break;
case '-':
R = Operand1 - Operand2;
break;
case '*':
R = Operand1 * Operand2;
break;
case '/':
try {
if( Operand2 == 0 )
throw "Division by zero not allowed";
R = Operand1 / Operand2;
}
catch(const char *Str)
{
cout << "\nBad Operator: " << Str;
}
break;
}
return R;
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::DisplayResult() const
{
double Result;
CalcResult();
Result = CalcResult();
// Display the result of the operation
cout << "\n" << Operand1 << " " << Operator << " "
<< Operand2 << " = " << Result;
}
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TCalculator Calc;
double Number1, Number2, Result;
char Oper;
cout << "This program allows you to perform an operation on two numbers\n";
cout << "To proceed, enter\n";
Calc.RequestOperands();
Calc.DisplayResult();
cout << "\nPress any key to continue...";
getch();
return 0;
}
//---------------------------------------------------------------------------
|
- Test the program and return to Bcb
|
Exception-Oriented Classes |
|
As in the earlier ProcessOrder() function, a method, and
each necessary method, of a class can handle its own exceptions locally,
perform the desired assignment, and send the result to the client that made
the call. Alternatively, just like our main() function had been
previously, you can create a member function of a class and let that
function act as the central point of the class. Such a typical function is
used to process transactions related to a class. To do this, implement the
other member functions and let them throw the exceptions they encounter.
While a member function is carrying its assignment, if it encounters an
exception, it can throw it to the central function where the call was
made. The central function would find the appropriate
catch that can handle the exception. This scenario can be
applied to set functions because a set function has the responsibility of
checking or validating the value carried by its corresponding member variable. If the value is invalid,
the set function can simply throw an exception and get out. Such a set
function would look like this: |
|
//---------------------------------------------------------------------------
void __fastcall TCleaningOrder::setShirts(const int Shirts)
{
if( isdigit(Shirts) )
throw Shirts;
NumberOfShirts = Shirts;
}
//---------------------------------------------------------------------------
|
This member function receives an argument
and checks it. If the sent argument is not a valid digit, the setShirts() method throws an
exception that carries the same argument that was sent. As you can see,
and as we have done with throwing exceptions so far, the setShirts()
method doesn't care who (that is, what) sent the wrong argument; it simply
throws it back
and stops there. On the other hand, if the argument that was sent is good,
the setShirts() method assigns it to the NumberOfShirts member variable
(remember that it is the setShirts() responsibility to control the
value that its corresponding member variable, in this case NumberOfShirts,
carries). The client function that sent the request (the request
consisted of asking the setShirts() function to validate the character)
will need to know what to do with the thrown exception.
Once a "central" function that passes
arguments to other member methods that validate them, this
"central" function doesn't need to throw any more exceptions,
but since the others will likely or possibly throw exceptions, our
"central function needs to be prepared to catch them and handle them
appropriately. In the following example, the ProcessOrder() method acts as
that "central" function:
|
|
//---------------------------------------------------------------------------
#include <iostream>
#include <iomanip>
#include <conio>
using namespace std;
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
// Constant prices of items, set by the store management
const double PriceShirt = 0.99;
const double PricePants = 1.75;
// Create an order object
struct TCleaningOrder
{
public:
void __fastcall setShirts(const int Shirts);
int __fastcall getShirts() { return NumberOfShirts; }
void __fastcall setPants(const int Pants);
int __fastcall getPants() { return NumberOfPants; }
void __fastcall setMisc(const int Misc);
int __fastcall getMisc() { return NumberOfMisc; }
__fastcall TCleaningOrder();
__fastcall ~TCleaningOrder();
void __fastcall ProcessOrder();
void __fastcall DisplayReceipt();
private:
int NumberOfShirts;
int NumberOfPants;
int NumberOfMisc;
double TotalPriceShirts;
double TotalPricePants;
double TotalPriceMisc;
double TotalOrder;
};
//---------------------------------------------------------------------------
__fastcall TCleaningOrder::TCleaningOrder()
: NumberOfShirts(0), NumberOfPants(0), NumberOfMisc(0)
{
}
//---------------------------------------------------------------------------
__fastcall TCleaningOrder::~TCleaningOrder()
{
}
//---------------------------------------------------------------------------
void __fastcall TCleaningOrder::setShirts(const int Shirts)
{
if( isdigit(Shirts) )
throw Shirts;
NumberOfShirts = Shirts;
}
//---------------------------------------------------------------------------
void __fastcall TCleaningOrder::setPants(const int Pants)
{
if( isdigit(Pants) )
throw Pants;
NumberOfPants = Pants;
}
//---------------------------------------------------------------------------
void __fastcall TCleaningOrder::setMisc(const int Misc)
{
if( isdigit(Misc) )
throw Misc;
NumberOfMisc = Misc;
}
//---------------------------------------------------------------------------
void __fastcall TCleaningOrder::ProcessOrder()
{
double PriceMisc;
int Shirts, Pants, Misc;
try {
cout << "Number of\n";
cout << "Shirts: ";
cin >> Shirts;
setShirts(Shirts);
cout << "Pairs of Paints: ";
cin >> Pants;
setPants(Pants);
cout << "Misc. Items(if none, type 0): ";
cin >> Misc;
setMisc(Misc);
// If there are miscalleanous items,...
if(getMisc() > 0)
{
// let the user determine the price of this misc item
cout << "Enter the price of each miscellanous item: ";
cin >> PriceMisc;
TotalPriceMisc = NumberOfMisc * PriceMisc;
}
else
TotalPriceMisc = 0.00;
TotalPriceShirts = NumberOfShirts * PriceShirt;
TotalPricePants = NumberOfPants * PricePants;
TotalOrder = TotalPriceShirts + TotalPricePants + TotalPriceMisc;
}
catch(const int n)
{
cout << n << " is not a valid number";
}
catch(...)
{
cout << "\nSomething went wrong - Too Bad";
}
}
//---------------------------------------------------------------------------
void __fastcall TCleaningOrder::DisplayReceipt()
{
cout << setiosflags(ios::fixed) << setprecision(2);
cout << " - Georgetown Cleaning Services -";
cout << "\n - Customer Receipt -";
cout << "\n============================";
cout << "\n Item\tNumber\tPrice";
cout << "\n----------------------------";
cout << "\n Shirts\t" << NumberOfShirts
<< "\t$" << TotalPriceShirts;
cout << "\n Pants\t" << NumberOfPants
<< "\t$" << TotalPricePants;
cout << "\n Misc\t" << NumberOfMisc
<< "\t$" << TotalPriceMisc;
cout << "\n============================";
cout << "\n Total Order:\t$" << TotalOrder;
}
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TCleaningOrder Order;
cout << " - Georgetown Cleaning Services -\n";
cout << " - Customer Order Processing -\n";
Order.ProcessOrder();
clrscr();
Order.DisplayReceipt();
cout << "\n\nPress any key to continue...";
getch();
return 0;
}
//---------------------------------------------------------------------------
|
Practical Learning: Improving Class' Exceptions |
|
For our exercise, we will create a member function for a
Calculator class. We use this function to proces a calculation. We also
prepare this function to handle various exceptions that can be (or would
be) thrown by other functions. The exceptions can be thrown based on a
wrong operand or a wrong operator. The class can be implemented in a
program as follows (some functions, such as the get methods were added to
allow external functions to communicate with the member variables of the
class). |
- Change the content of the file as follows:
//---------------------------------------------------------------------------
#include <iostream>
#include <conio>
using namespace std;
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
class TCalculator
{
public:
__fastcall TCalculator();
__fastcall TCalculator(char* Oper1, char Opr, char* Oper2);
void __fastcall RequestOperands();
void __fastcall setOperand1(const char* Oper1);
double __fastcall getOperand1() const;
void __fastcall setOperand2(const char *Oper2);
double __fastcall getOperand2() const;
void __fastcall setOperator(const char Opr);
char __fastcall getOperator() const;
void __fastcall setOperation(const char* x, const char p, const char* y);
double __fastcall CalcResult() const;
void __fastcall DisplayResult() const;
private:
double Operand1;
double Operand2;
char Operator;
};
//---------------------------------------------------------------------------
__fastcall TCalculator::TCalculator()
{
}
//---------------------------------------------------------------------------
__fastcall TCalculator::TCalculator(char* Oper1, char Opr, char* Oper2)
{
setOperand1(Oper1);
setOperator(Opr);
setOperand2(Oper2);
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::RequestOperands()
{
char Number1[40], Number2[40];
char Oper;
try {
cout << "To proceed, enter\n";
cout << "First Number: "; cin >> Number1;
cout << "An Operator: "; cin >> Oper;
cout << "Second Number: "; cin >> Number2;
setOperand1(Number1);
setOperator(Oper);
setOperand2(Number2);
CalcResult();
}
catch(const char n)
{
cout << "\nOperation Error: " << n << " is not a valid operator";
}
catch(const char *BadOperand)
{
cout << "\nError: " << BadOperand << " is not a valid number";
}
catch(const int n)
{
cout << "\nBad Operation: Division by " << n << " not allowed";
}
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::setOperand1(const char* Oper1)
{
for(unsigned int i = 0; i < strlen(Oper1); i++)
if( (!isdigit(Oper1[i])) && (Oper1[i] != '.') )
throw Oper1;
Operand1 = atof(Oper1);
}
//---------------------------------------------------------------------------
double __fastcall TCalculator::getOperand1() const
{
return Operand1;
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::setOperand2(const char* Oper2)
{
for(unsigned int i = 0; i < strlen(Oper2); i++)
if( (!isdigit(Oper2[i])) && (Oper2[i] != '.') )
throw Oper2;
Operand2 = atof(Oper2);
}
//---------------------------------------------------------------------------
double __fastcall TCalculator::getOperand2() const
{
return Operand2;
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::setOperator(const char Symbol)
{
if(Symbol != '+' && Symbol != '-' &&
Symbol != '*' && Symbol != '/')
throw Symbol;
Operator = Symbol;
}
//---------------------------------------------------------------------------
char __fastcall TCalculator::getOperator() const
{
return Operator;
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::setOperation(const char* Oper1,
const char Opr, const char* Oper2)
{
setOperand1(Oper1);
setOperator(Opr);
setOperand2(Oper2);
}
//---------------------------------------------------------------------------
double __fastcall TCalculator::CalcResult() const
{
double R;
// Perform an operation based on the user's choice
switch(Operator)
{
case '+':
R = Operand1 + Operand2;
break;
case '-':
R = Operand1 - Operand2;
break;
case '*':
R = Operand1 * Operand2;
break;
case '/':
try {
if( Operand2 == 0 )
throw "Division by zero not allowed";
R = Operand1 / Operand2;
}
catch(const char *Str)
{
cout << "\nBad Operator: " << Str;
}
break;
}
return R;
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::DisplayResult() const
{
double Result;
CalcResult();
Result = CalcResult();
// Display the result of the operation
cout << "\n" << Operand1 << " " << Operator << " "
<< Operand2 << " = " << Result;
}
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
TCalculator Calc;
double Number1, Number2, Result;
char Oper;
cout << "This program allows you to perform an operation on two numbers\n";
Calc.RequestOperands();
Calc.DisplayResult();
cout << "\nPress any key to continue...";
getch();
return 0;
}
//---------------------------------------------------------------------------
|
- Test the program and return to Bcb.
- Just as done with the functions, you can show that a function throws
one or more exceptions in its declaration. To do this, in the class,
on the right side of the function that throws an exception, type the
throw keyword followed by parentheses in which you would provide the
type of exception that the following would throw.
To apply this, change the function as follows:
//---------------------------------------------------------------------------
#include <iostream>
#include <conio>
using namespace std;
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
class TCalculator
{
public:
__fastcall TCalculator();
__fastcall TCalculator(char* Oper1, char Opr, char* Oper2);
void __fastcall RequestOperands();
void __fastcall setOperand1(const char* Oper1) throw(const char*);
double __fastcall getOperand1() const;
void __fastcall setOperand2(const char *Oper2) throw(const char*);
double __fastcall getOperand2() const;
void __fastcall setOperator(const char Opr) throw(const char);
char __fastcall getOperator() const;
void __fastcall setOperation(const char* x, const char p, const char* y);
double __fastcall CalcResult() const;
void __fastcall DisplayResult() const;
private:
double Operand1;
double Operand2;
char Operator;
};
//---------------------------------------------------------------------------
__fastcall TCalculator::TCalculator()
{
}
//---------------------------------------------------------------------------
__fastcall TCalculator::TCalculator(char* Oper1, char Opr, char* Oper2)
{
setOperand1(Oper1);
setOperator(Opr);
setOperand2(Oper2);
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::RequestOperands()
{
char Number1[40], Number2[40];
char Oper;
try {
cout << "To proceed, enter\n";
cout << "First Number: "; cin >> Number1;
cout << "An Operator: "; cin >> Oper;
cout << "Second Number: "; cin >> Number2;
setOperand1(Number1);
setOperator(Oper);
setOperand2(Number2);
CalcResult();
}
catch(const char n)
{
cout << "\nOperation Error: " << n << " is not a valid operator";
}
catch(const char *BadOperand)
{
cout << "\nError: " << BadOperand << " is not a valid number";
}
catch(const int n)
{
cout << "\nBad Operation: Division by " << n << " not allowed";
}
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::setOperand1(const char* Oper1) throw(const char*)
{
for(unsigned int i = 0; i < strlen(Oper1); i++)
if( (!isdigit(Oper1[i])) && (Oper1[i] != '.') )
throw Oper1;
Operand1 = atof(Oper1);
}
//---------------------------------------------------------------------------
double __fastcall TCalculator::getOperand1() const
{
return Operand1;
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::setOperand2(const char* Oper2) throw(const char*)
{
for(unsigned int i = 0; i < strlen(Oper2); i++)
if( (!isdigit(Oper2[i])) && (Oper2[i] != '.') )
throw Oper2;
Operand2 = atof(Oper2);
}
//---------------------------------------------------------------------------
double __fastcall TCalculator::getOperand2() const
{
return Operand2;
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::setOperator(const char Symbol) throw(const char)
{
if(Symbol != '+' && Symbol != '-' &&
Symbol != '*' && Symbol != '/')
throw Symbol;
Operator = Symbol;
}
//---------------------------------------------------------------------------
.
.
.
|
- Test the program and return to Bcb.
|
Separating the Object from its Implementation |
|
As we did in previous lessons, you
don't need to keep a class and its source file in the same file. You can
separate the header and the C++ source in separate files. This is done in
the same way you would do by creating a unit. |
Practical Learning: Creating a Class |
|
-
Create a new C++ Console Application using the Console Wizard.
- Create a folder called Exceptional2
- Save Unit1 as Main and save the project as Exceptions
- To create a new class, on the main menu, click File -> New... or
File -> New -> Other...
- From the New property sheet of the New Object dialog box,
double-click Unit
- Save the unit as Calculator
- Click the Calculator.h tab and change the content of the file as
follows:
//---------------------------------------------------------------------------
#ifndef CalculatorH
#define CalculatorH
//---------------------------------------------------------------------------
class TCalculator
{
public:
__fastcall TCalculator();
__fastcall TCalculator(char* Oper1, char Opr, char* Oper2);
void __fastcall RequestOperands();
void __fastcall setOperand1(const char* Oper1) throw(const char*);
double __fastcall getOperand1() const;
void __fastcall setOperand2(const char *Oper2) throw(const char*);
double __fastcall getOperand2() const;
void __fastcall setOperator(const char Opr) throw(const char);
char __fastcall getOperator() const;
void __fastcall setOperation(const char* x, const char p, const char* y);
double __fastcall CalcResult() const;
void __fastcall DisplayResult() const;
private:
double Operand1;
double Operand2;
char Operator;
};
//---------------------------------------------------------------------------
#endif
|
- Click the Calculator.cpp tab and change its content as follows:
//---------------------------------------------------------------------------
#include <iostream>
#include <conio>
using namespace std;
#pragma hdrstop
#include "Calculator.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
__fastcall TCalculator::TCalculator()
{
}
//---------------------------------------------------------------------------
__fastcall TCalculator::TCalculator(char* Oper1, char Opr, char* Oper2)
{
setOperand1(Oper1);
setOperator(Opr);
setOperand2(Oper2);
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::RequestOperands()
{
char Number1[40], Number2[40];
char Oper;
try {
cout << "To proceed, enter\n";
cout << "First Number: "; cin >> Number1;
cout << "An Operator: "; cin >> Oper;
cout << "Second Number: "; cin >> Number2;
setOperand1(Number1);
setOperator(Oper);
setOperand2(Number2);
CalcResult();
}
catch(const char n)
{
cout << "\nOperation Error: " << n << " is not a valid operator";
}
catch(const char *BadOperand)
{
cout << "\nError: " << BadOperand << " is not a valid number";
}
catch(const int n)
{
cout << "\nBad Operation: Division by " << n << " not allowed";
}
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::setOperand1(const char* Oper1) throw(const char*)
{
for(unsigned int i = 0; i < strlen(Oper1); i++)
if( (!isdigit(Oper1[i])) && (Oper1[i] != '.') )
throw Oper1;
Operand1 = atof(Oper1);
}
//---------------------------------------------------------------------------
double __fastcall TCalculator::getOperand1() const
{
return Operand1;
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::setOperand2(const char* Oper2) throw(const char*)
{
for(unsigned int i = 0; i < strlen(Oper2); i++)
if( (!isdigit(Oper2[i])) && (Oper2[i] != '.') )
throw Oper2;
Operand2 = atof(Oper2);
}
//---------------------------------------------------------------------------
double __fastcall TCalculator::getOperand2() const
{
return Operand2;
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::setOperator(const char Symbol) throw(const char)
{
if(Symbol != '+' && Symbol != '-' &&
Symbol != '*' && Symbol != '/')
throw Symbol;
Operator = Symbol;
}
//---------------------------------------------------------------------------
char __fastcall TCalculator::getOperator() const
{
return Operator;
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::setOperation(const char* Oper1,
const char Opr, const char* Oper2)
{
setOperand1(Oper1);
setOperator(Opr);
setOperand2(Oper2);
}
//---------------------------------------------------------------------------
double __fastcall TCalculator::CalcResult() const
{
double R;
// Perform an operation based on the user's choice
switch(Operator)
{
case '+':
R = Operand1 + Operand2;
break;
case '-':
R = Operand1 - Operand2;
break;
case '*':
R = Operand1 * Operand2;
break;
case '/':
try {
if( Operand2 == 0 )
throw "Division by zero not allowed";
R = Operand1 / Operand2;
}
catch(const char *Str)
{
cout << "\nBad Operator: " << Str;
}
break;
}
return R;
}
//---------------------------------------------------------------------------
void __fastcall TCalculator::DisplayResult() const
{
double Result;
CalcResult();
Result = CalcResult();
// Display the result of the operation
cout << "\n" << Operand1 << " " << Operator << " "
<< Operand2 << " = " << Result;
}
//---------------------------------------------------------------------------
|
- Click the Main.cpp tab and change its content as follows:
//---------------------------------------------------------------------------
#include <iostream>
#include <conio>
using namespace std;
#pragma hdrstop
#include "Calculator.h"
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
TCalculator Calc;
double Number1, Number2, Result;
char Oper;
cout << "This program allows you to perform an operation on two numbers\n";
Calc.RequestOperands();
Calc.DisplayResult();
cout << "\n\nPress any key to continue...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
|
- Test the program.
|
|
|