异常、类和继承以三种方式相互关联。
首先,可以像标准C++库所做的那样,从一个异常类派生出另一个。
其次,可以在类定义中嵌套异常类声明来组合异常。
第三,这种嵌套声明本身可以被继承,还可以作为基类。
接下来用一个例子进行相关的探索;
以下这个头文件声明了一个Sales类,它用于存储一个年份以及一个包含12个月销售数据的数组。
LabelledSales类是从Sales派生而来的。新增了一个用于存储数据标签的成员。
1 //sales.h -- exception and inheritance 2 #include <stdexcept> 3 #include <string> 4 5 class Sales 6 { 7 public: 8 enum {MONTHS = 12}; 9 class bad_index : public std::logic_error 10 { 11 12 }; 13 explicit Sales(int yy = 0); 14 Sales(int yy, const double * gr, int n); 15 virtual ~Sales() {} 16 int Year() const { return year;} 17 virtual double operator[] (int i) const; 18 virtual double & operator[] (int i); 19 20 private: 21 double gross[MONTHS]; 22 int year; 23 }; 24 25 26 class LabeledSales : public Sales 27 { 28 public: 29 class nbad_index : public Sales::bad_index 30 { 31 private: 32 std::string lbl; 33 public: 34 nbad_index(const std::string & lb, int ix, const std::string & s = "Index error in LabeledSales object "); 35 const std::string & label_val() const {return lbl;} 36 virtual ~nbad_index() throw() {} 37 } 38 explicit LabeledSales(const std::string & lb = "none", int yy = 0); 39 LabeledSales(const std::string & lb, int yy, const double * gr, int n); 40 virtual ~LabeledSales() {} 41 const std::string & Label() const {return label;} 42 virtual double operator[] (int i) const; 43 virtual double & operator[] (int i); 44 45 private: 46 std::string label; 47 48 };
分析以下头文件的细节;首先,符号常量位于Sales类的保护部分,这使得派生类能够使用这个值。
接下来,bad_index被嵌套在Sales类的公有部分中,这使得客户类的catch块可以使用这个类作为类型。
注意,在外部使用这个类型时,需要使用Sales::bad_index来标识。这个类是从logic_error类派生而来的,能够存储和报告数组索引的超界值。
nbad_index类被嵌套到LabeledSales的公有部分,这使得客户类可以通过LabeledSales::nbad_index来使用它。
它是从bad_inde类派生而来的,因此nbad_index归根结底也是从logic_error派生而来的。
这两个类都有重载的operator[]()方法,这些方法用于访问存储在对象中的数组元素,并在索引超界时引发异常。
接下来是源文件,是没有声明为内联的方法的实现。
1 //sales.cpp --Sales implementation 2 #include "sales.h" 3 using std::string; 4 5 6 Sales::bad_index::bad_index(int ix, const string & s) 7 : std::logic_error(s), bi(ix) 8 { 9 10 } 11 12 Sales::Sales(int yy) 13 { 14 year = yy; 15 for(int i = 0; i < Months; ++i) 16 gross[i] = 0; 17 } 18 19 Sales::Sales(int yy, const double * gr, int n) 20 { 21 year = yy; 22 int lim = (n< MONTHS)? n : MONTHS; 23 int i; 24 for (i=0;i<MONTHS;++i) 25 gross[i] = gr[i]; 26 // for i >n and i <MONTHS 27 for (;i < MONTHS;++i) 28 gross[i] = 0; 29 } 30 31 double Sales::operator[](int i) const 32 { 33 if(i<0 || i>=MONTHS) 34 throw bad_index(i); 35 return gross[i]; 36 } 37 38 double & Sales:;operator[] (int i) 39 { 40 if(i<0 || i>=MONTHS) 41 throw bad_index(i); 42 return gross[i]; 43 } 44 45 LabeledSales::nbad_index::nbad_index(const string & lb, int ix, const string & s):Sales::bad_index(ix,s) 46 { 47 lbl =lb; 48 } 49 50 LabeledSales::LabeledSales(const string & lb, int yy):Sales(yy) 51 { 52 label=lb; 53 } 54 55 LabeledSales::LabeledSales(const string & lb, int yy, const double * gr, int n):Sales(yy, gr, n) 56 { 57 label = lb; 58 } 59 60 double LabeledSales::operator[](int i) const 61 { 62 if(i<0 || i>=MONTHS) 63 throw nbad_index(Label(), i); 64 return Sales::operator[](i); 65 } 66 67 double & LabeledSales::operator[](int i) 68 { 69 if(i<0 || i>=MONTHS) 70 throw nbad_index(Label(), i); 71 return Sales::operator[](i); 72 }
接下来编写程序运行一下:
1 //use_sale.cpp --nested exceptions 2 #include <iostream> 3 #include "sales.h" 4 5 int main() 6 { 7 using std::cout; 8 using std::cin; 9 using std::endl; 10 11 double vals1[12] = 12 { 13 1220, 1100, 1122, 2212, 1232, 2334, 14 2884, 2393, 3302, 2922, 3002, 3544 15 }; 16 17 double vals[12] = 18 { 19 12,11,22,21,32,34, 20 28,29,33,29,32,35 21 }; 22 23 Sales sales1 (); 24 LabeledSales sales2(); 25 26 cout<<"First try block: "; 27 try 28 { 29 int i; 30 cout<<"Year = "<< sales1.Year() << endl; 31 for (i =0; i<12; ++i) 32 { 33 cout<<sales1[i]<<' '; 34 if (i % 6 == 5) 35 cout<<endl; 36 } 37 cout<<"Year = "<<sales2.Year()<<endl; 38 cout<<"Label = "<<sales2.Label()<<endl; 39 for (i = 0; i<=12; ++i) 40 { 41 cout<<sales2[i]<<' '; 42 if (i % 6 == 5) 43 cout<<endl; 44 } 45 cout<<"End of try block 1. "; 46 } 47 catch(LabeledSales::nbad_index & bad) 48 { 49 cout<<bad.what(); 50 cout<<"Company: "<<bad.label_val()<<endl; 51 cout<<"bad index: "<<bad.bi_val()<<endl; 52 } 53 catch(Sales::bad_index & bad) 54 { 55 cout<<bad.what(); 56 cout<<"bad index: "<<bad.bi_val()<<endl; 57 cout << " Next try block: "; 58 try 59 { 60 sales2[2] =37.5; 61 sales1[20]=23345; 62 cout<<"End of try block 2. "; 63 } 64 catch(LabeledSales::nbad_index & bad) 65 { 66 cout << bad.what(); 67 cout << "Company:" <<bad.label_val()<<endl; 68 cout << "bad index:" << bad.bi_val() << endl; 69 } 70 catch(Sales::bad_index & bad) 71 { 72 cout << bad.what(); 73 cout << "bad.bi_val()"<<endl; 74 } 75 cout << "done "; 76 return 0; 77 }