Custom Exception Classes in C++

You can define custom exception classes to model exceptions that cannot be adequately represented using C+ + standard exception classes.

C++ provides the exception classes listed in Figure 16.1. Use them whenever possible instead of creating your own exception classes. However, if you run into a problem that cannot be adequately described by the standard exception classes, you can create your own exception class. This class is just like any C++ class, but often it is desirable to derive it from exception videoNote or a derived class of exception so you can utilize the common features (e.g., the what()  Create custom exception function) in the exception class.

Let us consider the Triangle class for modeling triangles. The class UML diagram is shown in Figure 16.2. The class is derived from the GeometricObject class, which is an abstract class introduced in Section 15.9, “Abstract Classes and Pure Virtual Functions.”

A triangle is valid if the sum of any two sides is greater than the third side. When you attempt to create a triangle, or change a side of a triangle, you need to ensure that this property is not violated. Otherwise, an exception should be thrown. You can define the TriangleException class as in Listing 16.9 to model this exception.

Listing 16.9 TriangleException.h

1 #ifndef TRIANGLEEXCEPTION_H
2
#define TRIANGLEEXCEPTION_H
3
#include <stdexcept>
4
using namespace std;
5
6
class TriangleException: public logic_error
7 {
8     
public:
9     TriangleException(
double side1, double side2, double side3)
10    : logic_error(
“Invalid triangle”)
11    {
12       
this->side1 = side1;
13       
this->side2 = side2;
14       
this->side3 = side3;
15    }
16
17   
double getSide1() const
18    {
19       
return side1;
20    }
21
22   
double getSide2() const
23    {
24       
return side2;
25    }

26
27   
double getSide3() const
28    {
29       
return side3;
30    }
31
32   
private:
33   
double side1, side2, side3;
34 };
// Semicolon required
35
36
#endif

The TriangleException class describes a logic error, so it is appropriate to define this class to extend the standard logic_error class in line 6. Since logic_error is in the <stdexcept> header file, this header is included in line 3.

Recall that if a base constructor is not invoked explicitly, the base class’s no-arg con­structor is invoked by default. However, since the base class logic_error does not have a no-arg constructor, you must invoke a base class’s constructor to avoid compile errors in line 10. Invoking logic_error(“Invalid triangle”) sets an error message, which can be returned from invoking what() on an exception object.

The Triangle class can be implemented as follows in Listing 16.10.

Listing 16.10 Triangle.h

1 #ifndef TRIANGLE_H
2
#define TRIANGLE_H
3
#include “AbstractGeometricObject.h” // Defined in Listing 15.13
4 #include “TriangleException.h”
5 #include <cmath>
6
7
class Triangle: public GeometricObject
8 {
9     
public:
10    Triangle()
11    {
12       side1 = side2 = side3 =
1;
13    }
14
15    Triangle(
double side1, double side2, double side3)
16    {
17       
if (!isValid(side1, side2, side3))
18       
throw TriangleException(side1, side2, side3);
19
20       
this->side1 = side1;
21       
this->side2 = side2;

22       this->side3 = side3;
23    }
24
25   
double getSide1() const
26    {
27       
return side1;
28    }
29
30   
double getSide2() const
31    {
32       
return side2;
33    }
34
35   
double getSide3() const
36    {
37       
return side3;
38    }
39
40   
void setSide1(double side1)
41    {
42       
if (!isValid(side1, side2, side3))
43       
throw TriangleException(side1, side2, side3);
44
45       
this->side1 = side1;
46    }
47
48   
void setSide2(double side2)
49    {
50       
if (!isValid(side1, side2, side3))
51       
throw TriangleException(side1, side2, side3);
52
53       
this->side2 = side2;
54    }
55
56   
void setSide3(double side3)
57    {
58       
if (!isValid(side1, side2, side3))

59        throw TriangleException(side1, side2, side3);

60

61        this->side3 = side3;

62    }

63
64   
double getPerimeter() const
65    {
66       
return side1 + side2 + side3;
67    }
68
69   
double getArea() const
70    {
71       
double s = getPerimeter() / 2;
72       
return sqrt(s * (s – side1) * (s – side2) * (s – side3));
73    }
74
75   
private:
76   
double side1, side2, side3;
77
78   
bool isValid(double side1, double side2, double side3) const

79    {
80       
return (side1 < side2 + side3) && (side2 < side1 + side3) &&
81       (side3 < side1 + side2);
82     }
83 };
84
85
#endif

The Triangle class extends GeometricObject (line 7) and overrides the pure virtual func­tions getPerimeter and getArea defined in the GeometricObject class (lines 64-73).

The isValid function (lines 78-83) checks whether a triangle is valid. This function is defined private for use inside the Triangle class.

When constructing a Triangle object with three specified sides, the constructor invokes the isValid function (line 17) to check validity. If not valid, a TriangleException object is created and thrown in line 18. Validity also is checked when the functions setSide1, setSide2, and setSide3 are invoked. When invoking setSide1(side1), isValid(side1, side2, side3) is invoked. Here side1 is the new side1 to be set, not the current side1 in the object.

Listing 16.11 gives a test program that creates a Triangle object using its no-arg con­structor (line 9), displays its perimeter and area (lines 10-11), and changes its side3 to 4 (line 13), which causes a TriangleException to be thrown. The exception is caught in the catch block (lines 17-22).

Listing 16.11 TestTriangle.cpp

1 #include <iostream>
2
#include “Triangle.h”
3 using namespace std;
4
5
int main()
6 {
7   
try
8    {
9        Triangle triangle;
10       cout <<
“Perimeter is ” << triangle.getPerimeter() << endl;
11       cout <<
“Area is ” << triangle.getArea() << endl;
12
13       triangle.setSide3(
4);
14       cout <<
“Perimeter is ” << triangle.getPerimeter() << endl;
15       cout <<
“Area is ” << triangle.getArea() << endl;
16    }
17   
catch (TriangleException& ex)
18    {
19       cout << ex.what();
20       cout <<
” three sides are ” << ex.getSide1() << ” ”
21       << ex.getSide2() << ” ” << ex.getSide3() << endl;
22    }
23
24   
return 0;
25 }

The what() function is defined in the exception class. Since TriangleException is derived from logic_error, which is derived from exception, you can invoke what() (line 19) to display an error message on a TriangleException object. The TriangleException object contains the information pertinent to a triangle. This informa­tion is useful for handling the exception.

Source: Liang Y. Daniel (2013), Introduction to programming with C++, Pearson; 3rd edition.

Leave a Reply

Your email address will not be published. Required fields are marked *