📄 ch20.htm
字号:
105: {
106: Array intArray(9);
107: for (int j = 0; j< 100; j++)
108: {
109: intArray[j] = j;
110: cout << "intArray[" << j << "] okay..." << endl;
111: }
112: }
113: catch (Array::xBoundary)
114: {
115: cout << "Unable to process your input!\n";
116: }
117: catch (Array::xZero theException)
118: {
119: cout << "You asked for an Array of zero objects!" << endl;
120: cout << "Received " << theException.GetSize() << endl;
121: }
122: catch (Array::xTooBig theException)
123: {
124: cout << "This Array is too big..." << endl;
125: cout << "Received " << theException.GetSize() << endl;
126: }
127: catch (Array::xTooSmall theException)
128: {
129: cout << "This Array is too small..." << endl;
130: cout << "Received " << theException.GetSize() << endl;
131: }
132: catch (...)
133: {
134: cout << "Something went wrong, but I've no idea what!\n";
135: }
136: cout << "Done.\n";
137: return 0;
<TT>138: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: This array is too small...
Received 9
Done.
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>The declaration of <TT>xSize</TT>
has been modified to include a member variable, <TT>itsSize</TT>, on line 32 and
a member function, <TT>GetSize()</TT>, on line 30. Additionally, a constructor has
been added that takes an integer and initializes the member variable, as shown on
line 28.<BR>
The derived classes declare a constructor that does nothing but initialize the base
class. No other functions were declared, in part to save space in the listing.</P>
<P>The <TT>catch</TT> statements on lines 113 to 135 are modified to name the exception
they catch, <TT>theException</TT>, and to use this object to access the data stored
in <TT>itsSize</TT>.
<BLOCKQUOTE>
<P>
<HR>
<FONT COLOR="#000077"><B>NOTE: </B></FONT>Keep in mind that if you are constructing
an exception, it is because an exception has been raised: Something has gone wrong,
and your exception should be careful not to kick off the same problem. Therefore,
if you are creating an <TT>OutOfMemory</TT> exception, you probably don't want to
allocate memory in its constructor.
<HR>
</BLOCKQUOTE>
<P>It is tedious and error-prone to have each of these <TT>catch</TT> statements
individually print the appropriate message. This job belongs to the object, which
knows what type of object it is and what value it received. Listing 20.5 takes a
more object-oriented approach to this problem, using virtual functions so that each
exception "does the right thing."</P>
<P><A NAME="Heading21"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 20.5.Passing
by reference and using virtual functions in exceptions.</B></FONT>
<PRE><FONT COLOR="#0066FF">0: #include <iostream.h>
1:
2: const int DefaultSize = 10;
3:
4: class Array
5: {
6: public:
7: // constructors
8: Array(int itsSize = DefaultSize);
9: Array(const Array &rhs);
10: ~Array() { delete [] pType;}
11:
12: // operators
13: Array& operator=(const Array&);
14: int& operator[](int offSet);
15: const int& operator[](int offSet) const;
16:
17: // accessors
18: int GetitsSize() const { return itsSize; }
19:
20: // friend function
21: friend ostream& operator<<
22: (ostream&, const Array&);
23:
24: // define the exception classes
25: class xBoundary {};
26: class xSize
27: {
28: public:
29: xSize(int size):itsSize(size) {}
30: ~xSize(){}
31: virtual int GetSize() { return itsSize; }
32: virtual void PrintError()
33: {
34: cout << "Size error. Received: ";
35: cout << itsSize << endl;
36: }
37: protected:
38: int itsSize;
39: };
40:
41: class xTooBig : public xSize
42: {
43: public:
44: xTooBig(int size):xSize(size){}
45: virtual void PrintError()
46: {
47: cout << "Too big! Received: ";
48: cout << xSize::itsSize << endl;
49: }
50: };
51:
52: class xTooSmall : public xSize
53: {
54: public:
55: xTooSmall(int size):xSize(size){}
56: virtual void PrintError()
57: {
58: cout << "Too small! Received: ";
59: cout << xSize::itsSize << endl;
60: }
61: };
62:
63: class xZero : public xTooSmall
64: {
65: public:
66: xZero(int size):xTooSmall(size){}
67: virtual void PrintError()
68: {
69: cout << "Zero!!. Received: " ;
70: cout << xSize::itsSize << endl;
71: }
72: };
73:
74: class xNegative : public xSize
75: {
76: public:
77: xNegative(int size):xSize(size){}
78: virtual void PrintError()
79: {
80: cout << "Negative! Received: ";
81: cout << xSize::itsSize << endl;
82: }
83: };
84:
85: private:
86: int *pType;
87: int itsSize;
88: };
89:
90: Array::Array(int size):
91: itsSize(size)
92: {
93: if (size == 0)
94: throw xZero(size);
95: if (size > 30000)
96: throw xTooBig(size);
97: if (size <1)
98: throw xNegative(size);
99: if (size < 10)
100: throw xTooSmall(size);
101:
102: pType = new int[size];
103: for (int i = 0; i<size; i++)
104: pType[i] = 0;
105: }
106:
107: int& Array::operator[] (int offSet)
108: {
109: int size = GetitsSize();
110: if (offSet >= 0 && offSet < GetitsSize())
111: return pType[offSet];
112: throw xBoundary();
113: return pType[0];
114: }
115:
116: const int& Array::operator[] (int offSet) const
117: {
118: int size = GetitsSize();
119: if (offSet >= 0 && offSet < GetitsSize())
120: return pType[offSet];
121: throw xBoundary();
122: return pType[0];
123: }
124:
125: int main()
126: {
127:
128: try
129: {
130: Array intArray(9);
131: for (int j = 0; j< 100; j++)
132: {
133: intArray[j] = j;
134: cout << "intArray[" << j << "] okay...\n";
135: }
136: }
137: catch (Array::xBoundary)
138: {
139: cout << "Unable to process your input!\n";
140: }
141: catch (Array::xSize& theException)
142: {
143: theException.PrintError();
144: }
145: catch (...)
146: {
147: cout << "Something went wrong!\n";
148: }
149: cout << "Done.\n";
150: return 0;
<TT>151: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: Too small! Received: 9
Done.
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>Listing 20.5 declares a virtual
method in the <TT>xSize</TT> class, <TT>PrintError()</TT>, that prints an error message
and the actual size of the class. This is overridden in each of the derived classes.<BR>
<BR>
On line 141, the exception object is declared to be a reference. When <TT>PrintError()</TT>
is called with a reference to an object, polymorphism causes the correct version
of <TT>PrintError()</TT> to be invoked. The code is cleaner, easier to understand,
and easier to maintain.
<H3 ALIGN="CENTER"><A NAME="Heading23"></A><FONT COLOR="#000077">Exceptions and Templates</FONT></H3>
<P>When creating exceptions to work with templates, you have a choice: you can create
an exception for each instance of the template, or you can use exception classes
declared outside the template declaration. Listing 20.6 illustrates both approaches.</P>
<P><A NAME="Heading24"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 20.6. Using
exceptions with templates.</B></FONT>
<PRE><FONT COLOR="#0066FF">0: #include <iostream.h>
1:
2: const int DefaultSize = 10;
3: class xBoundary {};
4:
5: template <class T>
6: class Array
7: {
8: public:
9: // constructors
10: Array(int itsSize = DefaultSize);
11: Array(const Array &rhs);
12: ~Array() { delete [] pType;}
13:
14: // operators
15: Array& operator=(const Array<T>&);
16: T& operator[](int offSet);
17: const T& operator[](int offSet) const;
18:
19: // accessors
20: int GetitsSize() const { return itsSize; }
21:
22: // friend function
23: friend ostream& operator<< (ostream&, const Array<T>&);
24:
25: // define the exception classes
26:
27: class xSize {};
28:
29: private:
30: int *pType;
31: int itsSize;
32: };
33:
34: template <class T>
35: Array<T>::Array(int size):
36: itsSize(size)
37: {
38: if (size <10 || size > 30000)
39: throw xSize();
40: pType = new T[size];
41: for (int i = 0; i<size; i++)
42: pType[i] = 0;
43: }
44:
45: template <class T>
46: Array<T>& Array<T>::operator=(const Array<T> &rhs)
47: {
48: if (this == &rhs)
49: return *this;
50: delete [] pType;
51: itsSize = rhs.GetitsSize();
52: pType = new T[itsSize];
53: for (int i = 0; i<itsSize; i++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -