C++ Primer Plus (P52) pot

20 233 0
C++ Primer Plus (P52) pot

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

hold the value of the bad index. Note that the nested class declaration just describes the class; it doesn't create objects. The class methods will create objects of this class if they throw exceptions of the BadIndex type. Also note that the nested class is public. This allows the catch blocks to have access to the type. Listing 15.12 shows the new header file. The rest of the definition, aside from changing the class name, is the same as the definition of ArrayDb in Chapter 14, except that it qualifies the method prototypes to indicate which exceptions they can throw. That is, it replaces virtual double & operator[](int i); with virtual double & operator[](int i) throw(ArrayDbe::BadIndex &); and so on. (As with ordinary function arguments, it's usually better to pass references instead of objects when throwing exceptions.) Listing 15.12 arraydbe.h // arraydbe.h define array class with exceptions #ifndef ARRAYDBE_H_ #define ARRAYDBE_H_ #include <iostream> using namespace std; class ArrayDbE { private: unsigned int size; // number of array elements protected: double * arr; // address of first element public: class BadIndex // exception class for indexing problems { private: int badindex; // problematic index value public: This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. BadIndex(int i) : badindex(i) {} virtual void Report() const; }; ArrayDbE(); // default constructor // create an ArrayDbE of n elements, set each to val ArrayDbE(unsigned int n, double val = 0.0); // create an ArrayDbE of n elements, initialize to array pn ArrayDbE(const double * pn, unsigned int n); // copy constructor ArrayDbE(const ArrayDbE & a); virtual ~ArrayDbE(); // destructor unsigned int ArSize() const; // returns array size double Average() const; // return array average // overloaded operators // array indexing, allowing assignment virtual double & operator[](int i) throw(ArrayDbE::BadIndex &); // array indexing (no =) virtual const double & operator[](int i) const throw(ArrayDbE::BadIndex &); ArrayDbE & operator=(const ArrayDbE & a); friend ostream & operator<<(ostream & os, const ArrayDbE & a); } ; #endif Next, you must provide the class methods. These are the same methods used in Chapter 12 with the addition of some exception throwing. Because the overloaded [] operators throw exceptions instead of calling the exit() function, the program no longer needs to include the cstdlib file. Listing 15.13 shows the result. Listing 15.13 arraydbe.cpp // arraydbe.cpp ArrayDbE class methods #include <iostream> using namespace std; #include "arraydbe.h" This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. // BadIndex method void ArrayDbE::BadIndex::Report() const { cerr << "Out of bounds index value: " << badindex << endl; } // ArrayDbE methods // default constructor no arguments ArrayDbE::ArrayDbE() { arr = NULL; size = 0; } // constructs array of n elements, each set to val ArrayDbE::ArrayDbE(unsigned int n, double val) { arr = new double[n]; size = n; for (int i = 0; i < size; i++) arr[i] = val; } // initialize ArrayDbE object to a non-class array ArrayDbE::ArrayDbE(const double *pn, unsigned int n) { arr = new double[n]; size = n; for (int i = 0; i < size; i++) arr[i] = pn[i]; } // initialize ArrayDbE object to another ArrayDbE object ArrayDbE::ArrayDbE(const ArrayDbE & a) { size = a.size; arr = new double[size]; This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. for (int i = 0; i < size; i++) arr[i] = a.arr[i]; } ArrayDbE::~ArrayDbE() { delete [] arr; } double ArrayDbE::Average() const { double sum = 0; int i; int lim = ArSize(); for (i = 0; i < lim; i++) sum += arr[i]; if (i > 0) return sum / i; else { cerr << "No entries in score array\n"; return 0; } } // return array size unsigned int ArrayDbE::ArSize() const { return size; } // let user access elements by index (assignment allowed) double & ArrayDbE::operator[](int i) throw(ArrayDbE::BadIndex &) { // check index before continuing if (i < 0 || i >= size) throw BadIndex(i); return arr[i]; This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. } // let user access elements by index (assignment disallowed) const double & ArrayDbE::operator[](int i)const throw(ArrayDbE::BadIndex &) { // check index before continuing if (i < 0 || i >= size) throw BadIndex(i); return arr[i]; } // define class assignment ArrayDbE & ArrayDbE::operator=(const ArrayDbE & a) { if (this == &a) // if object assigned to self, return *this; // don't change anything delete arr; size = a.size; arr = new double[size]; for (int i = 0; i < size; i++) arr[i] = a.arr[i]; return *this; } // quick output, 5 values to a line ostream & operator<<(ostream & os, const ArrayDbE & a) { int i; for (i = 0; i < a.size; i++) { os << a.arr[i] << " "; if (i % 5 == 4) os << "\n"; } if (i % 5 != 0) os << "\n"; return os; This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. } Note that the exceptions now are objects instead of strings. Also note that these exception throws use the exception class constructor to create and initialize the exception objects: if (i < 0 || i >= size) throw BadIndex(i); // create, initialize a BadIndex object What about catching this kind of exception? The exceptions are objects, not character strings, so the catch block has to reflect that fact. Also, because the exception is a nested type, the code needs to use the scope resolution operator. try { } catch(ArrayDbE::BadIndex &) { } Listing 15.14 provides a short program demonstrating the process. Listing 15.14 exceptar.cpp // exceptar.cpp use the ArrayDbE class // Compile with arraydbe.cpp #include <iostream> using namespace std; #include "arraydbe.h" const int Players = 5; int main() { try { ArrayDbE Team(Players); cout << "Enter free-throw percentages for your 5 " "top players as a decimal fraction:\n"; int player; This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. for (player = 0; player < Players; player++) { cout << "Player " << (player + 1) << ": % = "; cin >> Team[player]; } cout.precision(1); cout.setf(ios_base::showpoint); cout.setf(ios_base::fixed,ios_base::floatfield); cout << "Recapitulating, here are the percentages:\n"; for (player = 0; player <= Players; player++) cout << "Player #" << (player + 1) << ": " << 100.0 * Team[player] << "%\n"; } // end of try block catch (ArrayDbE::BadIndex & bi) // start of handler { cout << "ArrayDbE exception:\n"; bi.Report(); } // end of handler cout << "Bye!\n"; return 0; } Compatibility Note Some compilers may not recognize the new form ios_base:: and will require ios:: instead. Note the second for loop deliberately exceeds the array bounds, triggering an exception. Here is a sample run: Enter free-throw percentages for your 5 top players as a decimal fraction: Player 1: % = 0.923 Player 2: % = 0.858 Player 3: % = 0.821 Player 4: % = 0.744 This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. Player 5: % = 0.697 Recapitulating, here are the percentages: Player #1: 92.3% Player #2: 85.8% Player #3: 82.1% Player #4: 74.4% Player #5: 69.7% ArrayDbE exception: Out of bounds index value: 5 Bye! Because the loop is inside the try block, throwing the exception terminates the loop as control passes to the second catch block following the try block. By the way, remember that variables defined in a block, including a try block, are local to the block. For example, the variable player is undefined once program control passes beyond the try block in Listing 15.15. Exceptions and Inheritance Inheritance interacts with exceptions in a couple of ways. First, if a class has publicly nested exception classes, a derived class inherits those exception classes. Second, you can derive new exception classes from existing ones. We'll look at both these possibilities in the next example. First, derive a LimitArE class from the ArrayDbE class. The LimitArE class will allow for array indexing to begin with values other than 0. This can be accomplished by storing a value representing the starting index and by redefining the functions. Internally, the array indexing still will begin with 0. But if, say, you specify 1900 as the starting index, the operator[]() method will translate an external index of 1908 to an internal index 1908—1900, or 8. Listing 15.15 shows the details. The BadIndex exception declared in the ArrayDbE class stored the offending index value. With variable index limits, it would be nice if the exception also stored the correct range for indices. You can accomplish this by deriving a new exception class from BadIndex: This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. class SonOfBad : public ArrayDbE::BadIndex { private: int l_lim; int u_lim; public: SonOfBad(int i, int l, int u) : BadIndex(i), l_lim(l), u_lim(u) {} void Report() const; // redefines Report() } ; You can nest the SonOfBad declaration in the LimitArE declaration. Listing 15.15 shows the result. Listing 15.15 limarre.h // limarre.h LimitArE class with exceptions #ifndef LIMARRE_H_ #define LIMARRE_H_ #include "arraydbe.h" class LimitArE : public ArrayDbE { public: class SonOfBad : public ArrayDbE::BadIndex { private: int l_lim; int u_lim; public: SonOfBad(int i, int l, int u) : BadIndex(i), l_lim(l), u_lim(u) {} void Report() const; } ; This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. private: unsigned int low_bnd; // new data member protected: // handle bounds checking virtual void ok(int i) const throw(ArrayDbE::BadIndex &); public: // constructors LimitArE() : ArrayDbE(), low_bnd(0) {} LimitArE(unsigned int n, double val = 0.0) : ArrayDbE(n,val), low_bnd(0) {} LimitArE(unsigned int n, int lb, double val = 0.0) : ArrayDbE(n, val), low_bnd(lb) {} LimitArE(const double * pn, unsigned int n) : ArrayDbE(pn, n), low_bnd(0) {} LimitArE(const ArrayDbE & a) : ArrayDbE(a), low_bnd(0) {} // new methods void new_lb(int lb) { low_bnd = lb;} // reset lower bound int lbound() { return low_bnd;} // return lower bound int ubound() { return ArSize() + low_bnd - 1;} // upper bound // redefined operators double & operator[](int i) throw(ArrayDbE::BadIndex &); const double & operator[](int i) const throw(ArrayDbE::BadIndex &); } ; #endif This design moves index checking from the overloaded [] methods to an ok() method that's called by the overloaded [] methods. C++ requires that the throw specification for virtual method redefined in the derived class match the throw specification in the base class. However, a base class reference can refer to a derived object. Therefore, although the LimitArE::ok() method throws a SonOfBad exception, the throw specifiers can list the ArrayDbe::BadIndex class. Listing 15.16 shows the class methods. Listing 15.16 limarre.cpp // limarre.cpp #include "limarre.h" This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks. [...]... appropriate In short, exceptions are the kind of feature that, like classes, can modify your approach to programming Newer C++ compilers are incorporating exceptions into the language For example, the exception header file (formerly exception.h or except.h) defines an exception class that C++ uses as a base class for other exception classes used to support the language Your code, too, can throw an exception... hierarchy of exception classes, arrange the order of the catch blocks so the most derived class exception is caught first and the base class exception is caught last The exception Class The main intent for C++ exceptions is to provide language-level support for designing fault-tolerant programs That is, exceptions make it easier to incorporate error handling into a program design rather than tacking on some... of making all the exception class declarations available with a using directive, you could use the scope resolution operator: class OutOfBounds : public std::exception The bad_alloc Exception and new C++ gives implementations two choices for handling memory allocation problems when using new The first choice, and once the only choice, is to have new return the null pointer if it can't satisfy a memory . to programming. Newer C++ compilers are incorporating exceptions into the language. For example, the exception header file (formerly exception.h or except.h) defines an exception class that C++ uses as. caught first and the base class exception is caught last. The exception Class The main intent for C++ exceptions is to provide language-level support for designing fault-tolerant programs. That. from the overloaded [] methods to an ok() method that's called by the overloaded [] methods. C++ requires that the throw specification for virtual method redefined in the derived class match

Ngày đăng: 07/07/2014, 06:20

Tài liệu cùng người dùng

Tài liệu liên quan