C++_异常8-异常、类和基础

时间:2023-01-23 21:25:14

异常、类和继承以三种方式相互关联。

首先,可以像标准C++库所做的那样,从一个异常类派生出另一个。

其次,可以在类定义中嵌套异常类声明来组合异常。

第三,这种嵌套声明本身可以被继承,还可以作为基类。

接下来用一个例子进行相关的探索;

以下这个头文件声明了一个Sales类,它用于存储一个年份以及一个包含12个月销售数据的数组。

LabelledSales类是从Sales派生而来的。新增了一个用于存储数据标签的成员。

 //sales.h  -- exception and inheritance
#include <stdexcept>
#include <string> class Sales
{
public:
enum {MONTHS = };
class bad_index : public std::logic_error
{ };
explicit Sales(int yy = );
Sales(int yy, const double * gr, int n);
virtual ~Sales() {}
int Year() const { return year;}
virtual double operator[] (int i) const;
virtual double & operator[] (int i); private:
double gross[MONTHS];
int year;
}; class LabeledSales : public Sales
{
public:
class nbad_index : public Sales::bad_index
{
private:
std::string lbl;
public:
nbad_index(const std::string & lb, int ix, const std::string & s = "Index error in LabeledSales object\n");
const std::string & label_val() const {return lbl;}
virtual ~nbad_index() throw() {}
}
explicit LabeledSales(const std::string & lb = "none", int yy = );
LabeledSales(const std::string & lb, int yy, const double * gr, int n);
virtual ~LabeledSales() {}
const std::string & Label() const {return label;}
virtual double operator[] (int i) const;
virtual double & operator[] (int i); private:
std::string label; };

分析以下头文件的细节;首先,符号常量位于Sales类的保护部分,这使得派生类能够使用这个值。

接下来,bad_index被嵌套在Sales类的公有部分中,这使得客户类的catch块可以使用这个类作为类型。

注意,在外部使用这个类型时,需要使用Sales::bad_index来标识。这个类是从logic_error类派生而来的,能够存储和报告数组索引的超界值。

nbad_index类被嵌套到LabeledSales的公有部分,这使得客户类可以通过LabeledSales::nbad_index来使用它。

它是从bad_inde类派生而来的,因此nbad_index归根结底也是从logic_error派生而来的。

这两个类都有重载的operator[]()方法,这些方法用于访问存储在对象中的数组元素,并在索引超界时引发异常。

接下来是源文件,是没有声明为内联的方法的实现。

 //sales.cpp  --Sales implementation
#include "sales.h"
using std::string; Sales::bad_index::bad_index(int ix, const string & s)
: std::logic_error(s), bi(ix)
{ } Sales::Sales(int yy)
{
year = yy;
for(int i = ; i < Months; ++i)
gross[i] = ;
} Sales::Sales(int yy, const double * gr, int n)
{
year = yy;
int lim = (n< MONTHS)? n : MONTHS;
int i;
for (i=;i<MONTHS;++i)
gross[i] = gr[i];
// for i >n and i <MONTHS
for (;i < MONTHS;++i)
gross[i] = ;
} double Sales::operator[](int i) const
{
if(i< || i>=MONTHS)
throw bad_index(i);
return gross[i];
} double & Sales:;operator[] (int i)
{
if(i< || i>=MONTHS)
throw bad_index(i);
return gross[i];
} LabeledSales::nbad_index::nbad_index(const string & lb, int ix, const string & s):Sales::bad_index(ix,s)
{
lbl =lb;
} LabeledSales::LabeledSales(const string & lb, int yy):Sales(yy)
{
label=lb;
} LabeledSales::LabeledSales(const string & lb, int yy, const double * gr, int n):Sales(yy, gr, n)
{
label = lb;
} double LabeledSales::operator[](int i) const
{
if(i< || i>=MONTHS)
throw nbad_index(Label(), i);
return Sales::operator[](i);
} double & LabeledSales::operator[](int i)
{
if(i< || i>=MONTHS)
throw nbad_index(Label(), i);
return Sales::operator[](i);
}

接下来编写程序运行一下:

 //use_sale.cpp  --nested exceptions
#include <iostream>
#include "sales.h" int main()
{
using std::cout;
using std::cin;
using std::endl; double vals1[] =
{
, , , , , ,
, , , , ,
}; double vals[] =
{
,,,,,,
,,,,,
}; Sales sales1 ();
LabeledSales sales2(); cout<<"First try block:\n";
try
{
int i;
cout<<"Year = "<< sales1.Year() << endl;
for (i =; i<; ++i)
{
cout<<sales1[i]<<' ';
if (i % == )
cout<<endl;
}
cout<<"Year = "<<sales2.Year()<<endl;
cout<<"Label = "<<sales2.Label()<<endl;
for (i = ; i<=; ++i)
{
cout<<sales2[i]<<' ';
if (i % == )
cout<<endl;
}
cout<<"End of try block 1.\n";
}
catch(LabeledSales::nbad_index & bad)
{
cout<<bad.what();
cout<<"Company: "<<bad.label_val()<<endl;
cout<<"bad index: "<<bad.bi_val()<<endl;
}
catch(Sales::bad_index & bad)
{
cout<<bad.what();
cout<<"bad index: "<<bad.bi_val()<<endl;
cout << "\nNext try block:\n";
try
{
sales2[] =37.5;
sales1[]=;
cout<<"End of try block 2.\n";
}
catch(LabeledSales::nbad_index & bad)
{
cout << bad.what();
cout << "Company:" <<bad.label_val()<<endl;
cout << "bad index:" << bad.bi_val() << endl;
}
catch(Sales::bad_index & bad)
{
cout << bad.what();
cout << "bad.bi_val()"<<endl;
}
cout << "done\n";
return ;
}