11

C++ Special Features

ERRORS AND EXCEPTIONS AND OPERATOR OVERLOADING

LEARNING OBJECTIVES

At the end of this chapter, you should be able to

  • Write objective-oriented C++ programs that incorporate errors and exceptions.

  • Write programs with your own errors and exceptions class to suit particular and individual needs.

  • Write programs with overloading of operators.

11.1 Introduction

Many of you would have come across a pop-up while using the Internet or operating system, wherein the pop message says “OS or Browser has experienced a serious problem and needs to be closed down. Error reporting is in process”. Indeed, error has occurred. Despite elaborate testing prior to delivery, errors cannot be prevented but they can be minimized. In this chapter, we will study of mechanism of C++ to handle errors and exceptions.

An important feature of any modern OOPs language is overloading. Overloading means making a function or operator perform more than one task, depending on the arguments supplied, at run-time. Function overloading is one such example. C++ has overloaded the operators too. Intrinsic operators have been overloaded thus enhancing the efficiency of language.

11.2 Errors and Exceptions

There are three types of errors that can crop up in a program:

  • Syntactical Errors: Can be easily detected and corrected by compilers.
  • Logical Errors: Arise due to the programmer not understanding flow of logic.
  • This can be corrected by extensive testing.
  • Bugs: These can be fixed by the programmer using assert() macros and debuggers available.

Exceptions, on the other hand, are unusual conditions that occur at run-time and can lead to errors that can crash a program. The exceptions can be classified as

Synchronous, i.e. those can be predicted. For example, array index going outside the permissible values can be easily detected because such errors occur only when you have executed the statement involving array index. The synchronous exception can occur at any one or more of the following situations:

  • Memory allocation exception
  • IO handling exception
  • Maths handling exception like division by zero

Asynchronous exceptions, those that cannot be predicted.

Generally, the resources required for the program are allocated at the very beginning and resources are demanded at run-time. Thus, it is likely that our program may exceed the initial allotment. As an example, consider allocated memory for an array. When such an exception occurs, we need a mechanism to carry such information to the area where recourses are allocated so that we can take corrective actions and prevent program crashing.

11.3 Try and Catch Blocks

C++ raises an exception object. For it to do so, we need to use a try block, wherever we expect likely exception. Catch blocks that follow try blocks catch the exception object and take remedial action.

Consider the case of allocating dynamic memory allocation for a two-dimensional matrix. Try will allocate dynamic memory. If it fails due to non-availability of memory, then it will throw the exception object. Catch block will catch the exception thrown by try block and take remedial measures. In the example that follows, we will show how to use try and catch blocks for allocation of memory for a two-dimensional matrix.

 

Example 11.1:   Use of Try and Catch Block. Allocation of Memory for a Two-dimensional Matrix

1. try
2. { A=new int * [m];
3. for (int i=0;i<m;i++)
4. A[i]=new int[n];
5. }catch (bad_alloc) { cout<<”
 bad allocation”<<endl;exit(1);}

 

Example 11.2:   A Try Block can Catch Multiple Exceptions Like IO Exception, Index Out of Bounds Exception, etc

try
{
// allocation code here
}
catch (bad allocation object){ }
catch ( File IO exception object) { }

 

Example 11.3:   Nesting of Try Block

try
  { // allocation code here
      try{// inner try block code here}
      catch ( File IO exception object) { }
  }
catch (bad allocation object){ }
catch ( File IO exception object) { }

11.4 Exception Classes

In the following example, we will demonstrate the use of exception handling in the case of divide by zero error that occurs at run-time. The example is that of calculation of density using the formula density = mass/area. The inputs are mass and radius. At run-time, if the radius is entered as zero, the program throws an exception object called DivideByZero();

Note that we have defined a class DivideByZero{} with an empty body so that we can use it as a tool to catch the exception and enter the catch block. In the catch block, we will inform the user and make a decent exit through exit(0) statement.

 

Example 11.4:   dividebyzero.cpp A Program to Demonstrate Exception Class – Divide by Zero

1.  #include<iostream> // for using cin and cout for input and output library
2.  using namespace std;
3.  class DivideByZero{} // exception class used to enter catch
4.  template <class T>
5.  T FindDensity(T mass , T radius);
6.  void main()
7.  { double mass, radius, area, density;
8.  while (1)
9.  { cout << “
 Enter mass in Kgs :”;
10. cin>> mass;
11. cout << “
 Enter radius < 0 to test divide by zero and exit> :”;
12. cin>> radius;
13. try
14. {if ( radius==0.0)
15. throw DivideByZero();
16. else
17. {area = 4*3.141581 *radius*radius;density = mass/area;}
18. }catch ( DivideByZero)
19. { cout<<”
 Dive by zero error has occurred :”<<endl;
20. cout<<”
 the parameters are : mass =”<<mass
21. <<”	”<<”radius =”<<radius<<endl;
22. cout<<”
 Exiting the programme:”<<endl;
23. exit(0);
24. }
25. cout<<”
 the parameters are : mass =”<<mass
26. <<”	”<<”radius =”<<radius<<”	”<<”density =”<<density<<endl;
27. cout<<“
 Normal execution of the programme.“<<endl;
28. }
29. } // end of main
/*Output: Enter mass in Kgs :25.00
Enter radius < 0 to test divide by zero and exit> :3.0
the parameters are : mass =25 radius =3 density =0.221049
Normal execution of the programme.
Enter radius < 0 to test divide by zero and exit> :0.0
Dive by zero error has occurred :
the parameters are : mass =45 radius =0
Exiting the programme:*/
Line No. 3: class DivideByZero{}; When an exception object is thrown, control passes to catch block, wherein corrective mechanisms are in place. To gain entry into catch block, we have declared and defined an exception class inside the main class. Note that this exception class has no body. Its sole purpose is to give entry into catch block.
Line No. 15: throw DivideByZero(); is inside a try block. This means that try block throws DivideByZero() object.
Lines No. 13–18: are try block and Lines No 18–24 are catch block.

We will use stack data structure to demonstrate errors and exception features. But before we do that, there is a need to understand the data structure called stack.

11.5 Stack Data Structure

Stack is a linear data structure. Data is inserted and extracted based on a technique called Last in first Out(LIFO) concept. As an example think of an activity of students submitting assignments to their teacher. The teacher will receive and pile them in a stack on the table and will start corrections from the top. Therefore, last in assignment gets service first. As you will see, computer systems depend on stack structure to solve several problems. Representation is shown in Figure 11.1.

 

Stack representation and terms

 

Figure 11.1 Stack representation and terms

 

Stack Operations

  • Create a stack.
  • Check if stack is full or empty. We cannot insert into a full stack. Neither can we extract from an empty stack.
  • Initialize the stack. For example, tos= –1, and tos = max –1; are initialization commands. Stack extends from 0 to (max –1).
  • Push (insert) an element onto stack if it is not full.
  • Pop(extract) an element from the stack if it is not empty.
  • Read from top of stack.
  • Display/print the entire stack.

As an example, while programming stack operations, we can include two exceptions, namely, stackfullexception and stackemptyexception.

class Stack
{ public: ………………….
  …………………..
  // Exception classes
        class stackfullerror {};
  class stackemptyerror {};
};

Try block and its associated catch block can be placed in the main program, where push and pop operations are contemplated. As shown below, try

{
  s.push(“Thunder”);
  cout<<s.top()<<endl;
  s.push(“Anand”);
  cout<<s.top()<<endl;
  s.push(“Ramesh”);
}

The following programs, 11.6, will highlight these features:

 

Example 11.5:   stackassign2.cpp Implements the Stack ADT Using Dynamic Arrays

1.  #include<iostream>
2.  #include<string>
3.  using namespace std;
4.  const int max_size=3;
5.  class Stack
6.  { public:
7.  Stack(); //default constructor
8.  ~Stack(); //destructor
9.  Stack& operator=(const Stack&); //Assignment operator overloading
10. int size() const; //returns number of elements in stack
11. int empty() const; //returns 1 if stack is empty
12. int & top(); //returns top of stack
13. void pop(); //pops top of stack
14. void push(const int &); //pushes element on top of stack
15. // exception classes
16. class stackfullerror {};
17. class stackemptyerror {};
18. private:
19. int* stack_array; //dynamic array
20. int tos; //top of stack pointer
21. int stack_size; //size of dynamic array
22. };
23. //default constructor
24. Stack :: Stack()
25. { stack_array = new int[max_size];
26. stack_size = max_size;
27. tos = -1;
28. }
29. //destructor
30. Stack:: ~Stack() {delete [] stack_array;}
31. Stack& Stack :: operator=(const Stack& S) // Assignment Operator
32. { stack_array = new int[S.stack_size];
33. tos = S.tos;
34. stack_size = S.stack_size;
35. for(int i =0 ; i<S.size(); i++)
36. stack_array[i] = S.stack_array[i];
37. return * this; // for chaining purpose
38. }
39. int Stack :: size() const {return tos+1;}
40. int Stack :: empty() const
41. { if(tos == -1)
42. return 1;
43. else return 0;
44. }
45. void Stack:: push(const int & val)
46. {if( tos<stack_size-1 )
47.  { tos++;
48.  stack_array[tos] = val;
49.  }
50.  else
51.  throw stackfullerror();
52. }
53. void Stack :: pop()
54.  { if(tos >= 0)
55.  tos--;
56.  else
57.  throw stackemptyerror();
58.  }
59. int& Stack :: top(){return(stack_array[tos]);}
60. void main()
61. { Stack s;
62.  //check for stack full exception
63.  try
64.  {s.push(10);s.push(20); s.push(30);
65.  }catch(Stack::stackfullerror)
66.  { cout<<”
stack full exception. Cannot be pursued on to stack:”<<endl;
67.  cout<<”
Exiting the catch block of stackfull exception ..”<<endl;
68.  }
69.  //overloaded assignment operator
70.  cout<<”
 Result of = operator on stack objects s & t ..”<<endl;
71.  Stack t;
72.  t=s; // assignment Operator
73.  cout<<”
 Elements of Stack s “<<endl;
74.  while(!s.empty())
75.  { cout<<s.top()<<endl;s.pop();}
76.  cout<<”
 Elements of Stack t after = operator”<<endl;
77.  while(!t.empty())
78.  { cout<<t.top()<<endl; t.pop();}
79. }//end of main
/* Output: Result of = operator on stack objects s & t ..
Elements of Stack s : 30 20 10
Elements of Stack t after = operator 30 20 10*/
Line No. 5: Declare a class for Stack class.
Lines No. 10 and 11: declare two functions called size() and empty()
Lines No. 12 and 13: declare two functions top() and pop()
Lines No. 16 & 17: Define class stackfullerror {} and class stackemptyerror {} inside class Stack
Line No. 19: declares a dynamic array called stack_array :int * stack_array;
Line No. 40: int Stack :: empty() const // empty() function definition
Lines No. 63–65: Try block wherein we have tried to push elements on to stack
Lines No. 65–68: catch block catches stackfullerror

11.6 Operator Overloading

Predefined operators such as +, –/, *, etc. are defined and provided by the compiler to work on intrinsic(basic) data types such as int, char, double, etc. We have also discussed at length while discussing the concept of function overloading that if a function can perform more than one task, then we can call it as overloading and it is an efficient way of utilizing scarce resources like primary memory. Operator overloading also improves the efficiency and throughput of the program by conserving the primary memory of C++.

If we can make these predefined operators work on user-defined data types such as classes, we would call this operator overloading. For example, consider a predefined operator +, and its normal operation:

int x=10, y=20;
int z = x + y ; // contents of x and y are added and placed in z
Now consider two complex numbers in polar form of representation:
Polar v1(25.0,53.50); // magnitude and angle theta
Polar v2(5.0, 45.00);
Polar v3;

11.6.1 Overloading of + Operator and * Operator

Operator + overloading means we can write v3 = v1 + v2. In that case, what would compiler do? Exactly what we tell the compiler to do in operator overloading function definition like

Convert both polar form vectors into Cartesian coordinates like r cos t + j sin t.

Add real terms of v1 and v2 and place them in v3.

Add imaginary terms of v1 and v2 and place them in v3.

Convert the resultant v3 into polar form.

For multiplication:

Convert both into polar form.

Multiply magnitude of polar1 & polar2 to get resultant magnitude.

Add angles of polar1 & polar2 to get resultant theta.

Declare resultant magnitude and resultant theta as a result of multiplication.

Let us attempt this interesting problem in our next problem. In this program, we will show how to overload operators + and * to perform operations on objects v1 and v2 so that we can write

v3=v1+v2; 
v3=v1*v2;

 

Example 11.6:   opplus.cpp A Program to Show Operators + , * Overloading

1. #include<iostream>
2. #include<cmath>
3. using namespace std;
4. class Polar
5. {// public accessory functions
6. public:
7.   Polar(){r=0.0;t=0.0;a=0.0;b=0.0;}
8.   Polar(double x, double y){a=x;b=y;r=0.0;t=0.0;}
9.   double GetA() const{return a;}
10.  double GetB() const {return b;}
11.  double GetR() const{return r;}
12.  double GetT() const {return t;}
13.  void ConvertToPolar(); // to convert to polar form
14.  void ConvertToCartesian(); // to convert to Cartesian form
15.  friend void DisplayPolar(const Polar &v); // to display in cartesian forms
16.  friend void DisplayCartesian(const Polar &v);
17.  Polar operator+(const Polar &v1);
18.  Polar operator*(const Polar &v1);
19. private:
20.  double r; //mag
21.  double t; //theeta
22.  double a; // real
23.  double b; // imaginary
24. };
25. void Polar::ConvertToPolar()
26. { double x=0.0;
    r=sqrt(a*a + b*b);
    x=atan(b/a);
    t= (7.0/22.0)*180.0*x; // PI radians equals 180 degrees
27. }
28. void Polar::ConvertToCartesian()
29. { double x=0.0;
      x=atan(b/a);
      a=r*cos(x);
      b=r*sin(x);
30. }
31. Polar Polar::operator+ (const Polar &v)
32. { Polar v3(a+v.GetA(),b+v.GetB()); return v3;}
33.   Polar Polar::operator* (const Polar &v)
34.  { Polar v3;
35.    float x=0.0;
36.    v3.r=r*v.GetR();
37.    v3.t=t+v.GetT();
38.    x = t*(7.0/22.0)*180;
39.    v3.a=r*cos(x);
40.    v3.b=r*sin(x);
41.    return v3;
42.  }
43. void DisplayCartesian(const Polar & v)
44. { cout<< «
 Vector in cartesian : real = «<<v.a<<» imaginary =»<<v.b<<endl; }
45. void DisplayPolar(const Polar & v)
46. { cout<< “
 Vector in polar form etc: magnitude = “<<v.r<<” Angle =”<<v.t<<endl;
47. }
48. void main()
49. { Polar v1(3.0,4.0),v2(3.0,4.0),v3 ,v4;
50.   cout<<»
 Given Vector V1 :»;
51.   DisplayCartesian(v1);
52.   cout<<»
 Given Vector V2 :»;
53.   DisplayCartesian(v2);
54.   v3=v1+v2;
55.   cout<<”
 after v1 + v2 :operator overloading ..”<<endl;
56.   DisplayCartesian(v3);
57.   v1.ConvertToPolar();
58.   v2.ConvertToPolar();
59.   DisplayPolar(v1);
60.   DisplayPolar(v2);
61.   v4=v1*v2;
62.   cout<<»
 after v1 * v2 :operator overloading ..»<<endl;
63.   DisplayPolar(v4);
64. }

/* Given Vector V1 :Vector in cartesian : real = 3 imaginary =4
Given Vector V2 : Vector in cartesian : real = 3 imaginary =4
after v1 + v2 :operator overloading ..
Vector in cartesian : real = 6 imaginary =8
Vector in polar form etc: magnitude = 5 Angle =53.1087
Vector in polar form etc: magnitude = 5 Angle =53.1087
after v1 * v2 :operator overloading ..
Vector in polar form etc: magnitude = 25 Angle =106.217*/

11.6.2 Operator << Overloading

We can write individual functions to display the object, as shown below, through the usage of DisplayPolar() function, but this is cumbersome. Instead, can we simply write cout<<v3 and still expect the same result? Operator << over loading achieves this result.

 

Example 11.7:   opcout.cpp To Demonstrate Overloading of << Operator

1. #include<iostream>
2. #include<cmath> // for maths related functions like sqrt,cos, tan, tan- etc
3. using namespace std;
4. // Declaration of class called Polar
5. class Polar
6. { public: Polar():r(0.0),t(0.0){} // Default constructor
7.    Polar( double f , double g):r(f),t(g){} // constructor
8.    ~Polar(){} // Default Destructor
9.    Polar operator*(const Polar &v1);
10.   void Display(ostream & src) const
11.   { src<<”Magnitude = “<<r<<”	”<<”Angle theeta =”<<t<<endl;}
12.   double GetR() const{return r;}
13.   double GetT() const {return t;}
14.   private:double r; t ; // magnitude & angle theeta
15. };
16. ostream & operator<<(ostream &src, const Polar v){ v.Display(src); return src;}
17. Polar Polar::operator* (const Polar &v)
18. { Polar v3;
19.    float x=0.0;
20.    v3.r=r*v.GetR();
21.    v3.t=t+v.GetT();
22.    return v3;
23. }
24. void main()
25. { Polar v1(5.0,53.0),v2(6.0,28.0),v3; // v1,v2,v3 is the object of Polar class
26.    cout<<“
The Given Vectors in Polar form form ….
“<<endl;
27.    cout<<“
Polar form vector v1 :“<<v1<<endl;
28.    cout<<“
Polar form vector 2 v2 :“<<v2<<endl;
29.    // multiply Polar Vectors v1 & v2 and store it in v3 using overloaded operator
30.    v3=v1*v2;
31.    cout<<“
v3=v1*v2 in Polar Form :“;
32.    cout<<v3;
33. }// end of main
34. /*Output: The Given Vectors in Polar form form ….
35. Polar form vector v1 :Magnitude = 5 Angle theeta =53
36. Polar form vector 2 v2 :Magnitude = 6 Angle theeta =28
37. v3=v1*v2 in Polar Form :Magnitude = 30 Angle theeta =81*/

11.6.3 What We Can Overload and What We Cannot Overload

All operators of C++ can be overloaded. We cannot overload the following operators:

  • Member function access operator : .
  • Dereferencing pointer to member : *
  • Conditional operator : ?
  • Scope resolution operator : ::
  • Sizeof()operator
  • All operators operating on a class must be overloaded except operators such as assignment = , address operator &, and comma operator , . Precedence of overloaded operators is exactly the same as that of normal operators.

11.6.4 Overloading Assignment Operator =

By now we appreciate what is meant by overloading. If we overload the assignment operator, we should be able to write in our code A = B where A and B are objects. In C++, we are aware that we can write assignment of several variables like

     double x = y = z = 3.141519;

Clearly after assigning the initial assignment as z = 3.141519, the operator must return the reference of what is assigned so that chaining can be continued and compiler can assign the values to y and thence to x. We also discussed that this pointer is always present when a function is invoked by the object and we can conveniently make use of this pointer to return the reference.

Polar & Polar :: operator = ( const Polar & src)
  { r = src.r; t = src.t;
    return *this; } // here we are returning ref for chaining explained above

As a second example, look at the problem in Example 11.6 discussed above wherein we have used operator = overloading

  9 Stack& operator=(const Stack&); //Assignment operator overloading
 31 Stack& Stack :: operator=(const Stack& S) // Assignment Operator
 32 { stack_array = new int[S.stack_size];
 33 tos = S.tos;
 34 stack_size = S.stack_size;
 35 for(int i =0 ; i<S.size(); i++)
 36 stack_array[i] = S.stack_array[i];
 37 return * this; // for chaining purpose
 38 }
Line No. 9: is a prototype declaration
Line No. 32: allocates space for new integer array as per S stack size
Line No. 33: equates S.stack_size to stck_size
Lines No. 35–36: get the array values
Line No. 37: returns a reference * this

If we are using templates, the assignment operator for a class called Stack in Example 11.4 looks like the following:

template <class T>
Stack<T>& Stack<T> :: operator=(const Stack& S)
{ stack_array = new T[S.stack_size];
  tos = S.tos;
  stack_size =    S.stack_size;
  for(int i =0 ; i<size; i++)
  stack_array[i] = S.stack_array[i];
  return *this;}

11.7 Pre- and Post-increment Operator Overloading

While end result is the same, C++ treats pre- and post-increment operators differently.

For pre-increment operators, the syntax is: Height & operator ++ (); //pre fix
For post-increment operators, the syntax is: Height & operator ++ (int);// post fix

Note that the argument int shown in case of post-increment operators is a dummy. It is used by compiler just to distinguish from pre-increment operators.

 

Example 11.8:   prepostfix.cpp Demonstrates Operator ++ Overloading.ence

1.  #include<iostream>
2.  #include<cmath> // for maths related functions like sqrt,cos , tan , tan- etc
3.  using namespace std;
4.  class Height {
5.  public:
6.  Height(float h);
7.  Height & operator ++ (); //pre fix
8.  Height & operator ++ (int); // post fix
9.  ~Height(); // Destructor
10. Height(Height const& m); // Copy constructor
11. Height& operator= (Height const& m); // Assignment operator
12. float GetHeight() const { return yourHeight;}
13. private:float yourHeight;
14. };
15. inline Height::Height(float h):yourHeight (h){}
16. inline Height::~Height() {} // Destructor
17. Height & Height::operator++ (){ ++yourHeight;return * this;}
18. Height & Height::operator ++ (int) {yourHeight++;return * this;}
19. void main()
20. { Height Ramesh(179.0),Gautam(172.0),Anand(171); // three objects created
21.   cout<<”
 Given Height…”<<endl;
22.   cout <<Ramesh.GetHeight()<<” : “<<Anand.GetHeight()<<” : “<<Gautam.GetHeight()<<endl;
23.   ++Ramesh;++Anand;++Gautam;
24.   cout<<”
 Height after prefix ++ overloading…”<<endl;
25.   cout <<Ramesh.GetHeight()<<” : “<<Anand.GetHeight()<<” : “<<Gautam.GetHeight()<<endl;
26.   Ramesh++;Anand++;Gautam++;
27.   cout<<”
 Height after postfix ++ overloading…”<<endl;
28.   cout <<Ramesh.GetHeight()<<” : “<<Anand.GetHeight()<<” : “<<Gautam.GetHeight()<<endl;
29. }
    /*Output: Given Height…179 : 171 : 172
    Height after prefix ++ overloading…180 : 172 : 173
    Height after postfix ++ overloading…181 : 173 : 174*/
Lines No. 17 and 18: Pre- and post-increment operators definition. Observe that your Height has been increased and *this (reference object) has been returned

11.8 Overloading Operators New and Delete

We are aware from our study of dynamic memory allocation that new operator is used for allocation of memory in heap memory. The syntax for new and delete operators is presented here:

  int *x = new int; // creation and allocation of heap memory
  *x=25; // assign value
  Alternately, we can use a single statement
  int *x = new int(12); allocate value 12 to pointer variable on heap memory
  ……………………
  delete x; // q pointer has been deleted

  For array declarations : //x is a pointer variable pointing to array by name x
  int *x =new int[12]; // having 12 contiguous locations.
  …………………….
  delete [] x; // deletion of pointer to an array

In the example that follows, we will show overloading of new and delete operators. As we are overloading new and delete operations, for memory allocation, we cannot use their original definitions. Instead, we use malloc() and free() functions from C language. The syntax is shown below:

  int *x ; // x is a pointer variable
  //allocate dynamic memory space using malloc()
  x = (int *)malloc( 12 *sizeof(int));
  ……………………..
  free(x); // delete the memory allocated

 

Example 11.9:   Stundent1.cpp A program to Overload New and Delete

1.  #include <iostream>
2.  #include <cstdlib> // for using malloc() & free operators
3.  #include <new> // including new fro c standard library
4.  using namespace std;
5.  class Stundent
6.  {public:
7.  Stundent() {rollNo = marks = 0;} //default constructor
8.  Stundent(int a, int b) {rollNo = a;marks = b;}
9.  void Display()
10. {cout <<”Roll No :”<<rollNo << “ Marks : “<<marks << endl;}
11. int GetrollNo()const { return rollNo;}
12. int Getmarks()const { return marks;}
13. void * operator new(size_t size);
14. void operator delete(void *std);
15. private :
16.  int rollNo, marks;
17. };
18. // overloaded new operator
19. void *Stundent::operator new(size_t size)
20. { void *std;
21.   cout << “In overloaded new.
”;
22.   std = malloc(size); // we are using malloc because we are overloading new
23.   if(!std)
24.   {bad_alloc e; throw e;}
25.   return std;
26. }
27. // delete operator overloaded
28. void Stundent::operator delete(void *std)
29.  { cout << “In Side overloaded delete.
”; free(std);}
30. void main()
31. { Stundent *std;
32. try {
33.   std = new Stundent (50595, 89);
34.   }catch (bad_alloc e) {cout << “Allocation error for obj1.
”;exit(1);}
35. std->Display();
36. delete std; // free an object
37. }
/*Output: In overloaded new.
Roll No :50595 Marks : 89
In Side overloaded delete.*/
Lines No. 13 and 14: void * operator new(size_t size); void operator delete(void *std); are prototypes for new and delete operators.
Lines No. 19–26: Definition for new operator. Line No 21 uses malloc function of C language for allocation space demanded by size. Also note that at line no 19, size_t is a data type defined in all include definitions supplied by compiler writers. It is equivalent to int.
Lines No. 23–26: show use of exception called bad_alloc, which throws an exception object e. The exception object is caught at line No 34.
Line No. 28: shows overloading of delete operator, which uses free() function of C.

11.9 Conversion (Casting) Operators

There are many occasions wherein an object of a class, say class number, needs to be converted to an object of string class. Conversion operators are useful in this case. It means userdefined objects such as classes and structures, etc., can be type casted to other objects by a facility called conversion operators. Conversion operator has to be a non-static member function (why?). For example:

Student std; // an object of Student
Operator char * () const; // converts std into char *
Operator int() const; // converts std into int

Operator Person() const; // converts std into an object of user-defined class Person ;

Const implies that conversion operator cannot change the original object. Note also that conversion operator does not have any return type. Compiler automatically converts object to char * when it sees the command operator char *(). Note also that overloaded conversion operators can be used to convert user-defined object into fundamental data type.

 

Example 11.10:   //convop.cpp A Program to Show Conversion Operator

1.  #include<iostream>
2.  #include<cstring>
3.  using namespace std;
4.  class OwnString
5.  { public:
6.    OwnString();    //default constructor
7.    OwnString(const char *s){stg=s;}; // constructor with argument
8.  operator const char *() {return stg;} // conversion operator to convert to ctype string
9.  private:
10.   const char *stg;
11.   int size;
12. };
13. void main()
14. {  OwnString stg(“Example of conversion Operator”);
15.    int n = strcmp(stg,”Example”);
16.    cout<<”Strings are NOT same : “<<n<<endl;
17.    n=strcmp(stg,”Example of conversion Operator”);
18.    cout<<”Strings are same : “<<n<<endl;
19. }
/*Output
Strings are NOT same : 1 : Strings are same : 0*/
Line No. 7: is overloaded constructor
Line No. 8: conversion operator that returns stg of type const char *(ctype) so that we can use it with strcmp in line no. 15 and 17.

11.10 Summary

  1. Errors are of three types: syntactical errors, logical errors and bugs.
  2. Syntactical errors can be easily detected and corrected by compilers.
  3. Logical errors arise due to the prog rammer not understanding the flow of logic. This can be corrected by extensive testing.
  4. Exceptions are unusual conditions that occur at run-time and can lead to errors that can crash a program. They can be classified as synchronous and asynchronous exceptions.
  5. Synchronous exceptions are those that can be predicted. They occur due to one or more of reasons like memory allocation, IO handling and exceptions such as divide by zero, etc.
  6. Asynchronous exceptions are those that cannot be predicted.
  7. Try and catch blocks are used to address problems arising out of errors and exceptions. Wherever error or exception is likely, the programmer includes a try block. Try block detects the errors and exceptions and throws error/exception objects. A try block can catch multiple exceptions and it can be nested.
  8. Catch block catches error/exception objects and takes remedial actions.
  9. Exception objects are used to gain entry into catch blocks.
  10. Operator overloading refers to basic operators performing operations on user-defined data types like lasses and objects in addition to intrinsic data types.
  11. Input and output operators like << and >> can be overloaded to operate on objects in conjunction with cin and cout objects of iostream.
  12. The operators that cannot be overloaded are: dot operator (.), * , ?, and ::
  13. Conversion operators can be used to convert objects of a class into objects of another class or into fundamental type.

Exercise Questions

Objective Questions

  1. Which of the following statements are valid function overloading?
    1. Same function name with different no of arguments.
    2. Same function name with different types of arguments.
    3. Same function name with same arguments but different return types.
    4. Same function name with different arguments and different return types.
    1. i and ii
    2. ii and iii
    3. iii
    4. i and iv
  2. Which of the following statements are true about data types of C++ errors and exceptions?
    1. Errors can be prevented
    2. Errors can be minimized
    3. Synchronous errors can be predicted
    4. Asynchronous errors can be predicted
    1. i and ii
    2. ii and iii
    3. ii, iii and iv
    4. i and iv
  3. Which of the following statements are valid with respect to C++ operator overloading?
    1. Basic operators work on basic data types.
    2. Basic operators work on basic data types and also user-defined data types.
    3. All operators of C++ can be overloaded.
    4. Overloading of operator is an OOPS feature.
    1. i, ii and iv
    2. ii and iii
    3. iii and iv
    4. i and iv
  4. Which of the following statements are valid with respect to C++ errors?
    1. Synchronous errors can be detected by compiler.
    2. Asynchronous errors can be detected by compiler.
    3. Logical errors can be detected by compiler.
    4. Bugs can be detected by compiler.
    1. i, ii and iv
    2. ii and iii
    3. iii and iv
    4. i and iv
  5. Which of the following statements are valid with respect to C++ exceptions?
    1. Synchronous errors cannot be predicted.
    2. Asynchronous errors cannot be predicted by compiler.
    3. IO exception is a synchronous exception.
    4. Resource allocation is done in the beginning and exception occurs at run-time.
    1. i, ii and iv
    2. ii, iii and iv
    3. iii and iv
    4. i and iv
  6. Exception objects are thrown by
    1. Try block
    2. Catch block
    3. IO block
    4. Exception class
  7. Remedial and corrective actions on the exception caught are handled by
    1. Try block
    2. Catch block
    3. IO block
    4. Exception class
  8. Which of the following operators cannot be overloaded?
    1. [ ]
    2. : :
    3. −>
    4. Dereferencing pointer to member *
    1. i, ii and iv
    2. ii, iii and iv
    3. ii and iv
    4. i and iv
  9. ? operator can be overloaded               TRUE/FALSE
  10. Bugs are a type of exception                TRUE/FALSE
  11. Which of the following are true in respect of operator overloading?
    1. >> & << are stream extraction operators
    2. >> & << are left shift & right shift operators
    3. both i) and ii)
    4. Meaning based on the context
    1. i
    2. ii
    3. iii
    4. iii and iv
  12. Which of the following statements are true with respect to conversion operators?
    1. Conversion operators are stati(c)
    2. Objects of one class can be converted to object of another class.
    3. Objects of one class cannot be converted to fundamental data types.
    4. Fundamental data types can also be converted into object of a class
    1. ii and iv
    2. ii and iii
    3. i and iii
    4. iii and iv

    Short-answer Questions

  13. Distinguish errors, exceptions.
  14. Differentiate synchronous and asynchronous exceptions.
  15. What are logical errors?
  16. What are bugs? How can they be minimized?
  17. Differentiate roles of try and catch blocks.
  18. What is the role of exception object?
  19. What is operator overloading?
  20. Why does OOPS language support operator overloading?
  21. Which of the operators cannot be overloaded? And why?

    Long-answer Questions

  22. Explain what are errors and exceptions.
  23. Explain how error handling is carried out in C++.
  24. Explain different modes of usage of try and catch blocks with examples.
  25. Explain operator overloading with suitable examples.
  26. Explain working of new and delete operator overloading with examples.
  27. What is conversion operator? Explain with examples.
  28. Compare functions and operator overloading for solving a problem. Which is better and why?

    Assignment Questions

  29. Implement a class called array with functionality such as find() sort() insert() and delete() with exception class such as ArrayOutOfBound { }and IOException { }.
  30. Write a cpp having an exception class called Insufficientfund { }. Your application should raise exception object if there no sufficient funds in the user's bank account. The exception object to give a suitable message.
  31. Implement queue data structure with class QueFull{ }and class QueEmpty{ }. Exception classes. Hint: Use an array implementation for queue. The elements in the array are serviced on first come first serve basis. Insertion of an element is at the end and removal for service is from the front.
  32. Implement a class called Array. Demonstrate the operator overloading for functionality such as addition, multiplication by a scalar, dot product and cross product.
  33. Implement a class called Rational with operator overloading for: + , = = , != operators.
  34. Implement a class called String with all necessary operator overloading.

Solutions to Objective Questions

  1. c
  2. b
  3. a
  4. d
  5. b
  6. a
  7. b
  8. a
  9. False
  10. True
  11. d
  12. a
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.136.18.218