In object-oriented programming languages the main technique for expressing specialization and generalization is the inheritance hierarchy. Inheritance in exceptions are particularry important for groupping exceptions in catch handlers.
try { ... } catch( Der1 d1 ) { ... } catch( Der2 d2 ) { ... } catch( Der3 d3 ) { ... } catch( Base b ) { ... } // example1: class net_error { ... }; class file_error { ... }; class nfs_error : public net_error, public file_error { ... }; void f() { try { ... } catch( nfs_error nfs ) { ... } catch( file_error fe ) { ... } catch( net_error ne ) { ... } } // example2: #ifndef MATRIX_H #define MATRIX_H #include <string> #include <sstream> #include <stdexcept> struct matrixError { matrixError( std::string r) : reason(r) { } const std::string reason; }; struct indexError : public matrixError, public std::out_of_range { indexError( int i, const char *r="Bad index") : matrixError(r), out_of_range(r), index(i) { } const char *what() const throw() { std::ostringstream os; os << std::out_of_range::what(); os << ", index = " << index; return os.str().c_str(); } virtual ~indexError() throw () { } int index; }; struct rowIndexError : public indexError { rowIndexError(int i) : indexError( i, "Bad row index") { } }; struct colIndexError : public indexError { colIndexError(int i) : indexError( i, "Bad col index") { } }; template <class T> class matrix { public: matrix( int i, int j ); matrix( const matrix &other); ~matrix(); matrix operator=( const matrix &other); int rows() const { return x; } int cols() const { return y; } T& at( int i, int j) throw(indexError); T at( int i, int j) const throw(indexError); T& operator()( int i, int j); T operator()( int i, int j) const; matrix operator+=( const matrix &other); private: int x; int y; T *v; void copy( const matrix &other); void check( int i, int j) const throw(indexError); }; template <class T> matrix<T>::matrix( int i, int j) { x = i; y = j; v = new T[x*y]; } template <class T> matrix<T>::matrix( const matrix &other) { copy( other); } template <class T> matrix<T>::~matrix() { delete [] v; } template <class T> matrix<T> matrix<T>::operator=( const matrix &other) { if ( this != &other ) { const int oldx = x; const int oldy = y; const T *oldv = v; try { copy( other); delete [] oldv; } catch(...) { x = oldx; y = oldy; delete [] v; v = oldv; throw; } } return *this; } template <class T> void matrix<T>::copy( const matrix &other) { x = other.x; y = other.y; v = 0; v = new T[x*y]; for ( int i = 0; i < x*y; ++i ) v[i] = other.v[i]; // possible memory leak at v } template <class T> void matrix<T>::check( int i, int j) const throw( indexError ) { if ( i < 0 || i >= x ) throw rowIndexError(i); if ( j < 0 || j >= y ) throw colIndexError(j); } template <class T> T& matrix<T>::at( int i, int j) throw(indexError) { check(i,j); return operator()(i,j); } template <class T> T matrix<T>::at( int i, int j) const throw( indexError) { check(i,j); return operator()(i,j); } template <class T> T& matrix<T>::operator()( int i, int j) { return v[i*y + j]; } template <class T> T matrix<T>::operator() ( int i, int j) const { return v[i*y + j]; } template <class T> matrix<T> matrix<T>::operator+=( const matrix &other) { for ( int i = 0; i < x*y; ++i ) v[i] += other.v[i]; return *this; } template <class T> matrix<T> operator+( const matrix<T> &left, const matrix<T> &right) { matrix<T> temp(left); temp += right; return temp; } #endif /* MATRIX_H */