Листинг 20.3. Наследование исключений



1: #include <iostream.h>

2:

3: const int DefaultSize = 10;

4:

5: class Array

6: {

7: public:

8: // конструкторы

9: Array(int itsSize = DefaultSize);

10: Array(const Array &rhs);

11: ~Array() { delete [] pType;}

12:

13: // операторы

14: Array& operator=(const Array&);

15: int& operator[](int offSet);

16: const int& operator[](int offSet) const;

17:

18: // методы доступа

19: int GetitsSize() const { return itsSize; }

20:

21: // функция-друг

22: friend ostream& operator<< (ostream&, const Array&);

23:

24: // определения классов исключений

25: class xBoundary { };

26: class xSize { };

27: class xTooBig : public xSize { };

28: class xTooSmall : public xSize { };

29: class xZero : public xTooSmall { };

30: class xNegative : public xSize { };

31: private:

32: int *pType;

33: int itsSize;

34: };

35:

36:

37: Array::Array(int size):

38: itsSize(size)

39: {

40: if (size — 0)

41: throw xZero();

42: if (size > 30000)

43: throw xTooBig();

44: if (size <1)

45: throw xNegative();

46: if (size < 10)

47: throw xTooSmall();

48:

49: pType = new int[size];

50: for (int i = 0; i<size; i++)

51: pType[i] = 0;

52: }

53:

54: int& Array::operator[](int offSet)

55: {

56: int size = GetitsSize();

57: if (offSet >= 0 && offSet < GetitsSize())

58: return pType[offSet];

59: throw xBoundary();

60: return pType[0]; // требование компилятора

61: }

62:

63:

64: const int&Array::operator[](int offSet) const

65: {

66: int mysize = GetitsSize();

67: if (offSet >= 0 && offSet < GetitsSize())

68: return pType[offSet];

69: throw xBoundary();

70:

71: return pType[0]; // требование компилятора

72: }

73:

74: int main()

75: {

76:

77: try

78: {

79: Array intArray(0);

80: for (int j = 0; j< 100; j++)

81: {

82: intArray[j ] = j;

83: cout << "intArray[" << j << "] okay...\n";

84: }

85: }

86: catch (Array::xBoundary)

87: {

88: cout << "Unable to process your input!\n";

89: }

90: catch (Array::xTooBig)

91: {

92: cout << "This array is too big...\n";

93: }

94:

95: catch (Array::xTooSmall)

96: {

97: cout << "This array is too small...\n";

98: }

99: catch (Array::xZero)

100: {

101: cout << "You asked for an array";

102: cout << " of zero objects!\n";

103: }

104:

105:

106: catch (.. .)

107: {

108: cout << "Something went wrong!\n";

109: }

110: cout << "Done.\n";

111: return 0;

112: }

 

Результат:

This array is too small...

Done.

 

Анализ: Здесь существенно изменены строки 27—30, где устанавливается иерархия классов. Классы xTooBig, xTooSmall и xNegative произведены от класса xSize, а класс xZero — от класса xTooSmall.

Класс Array создается с нулевым размером, но что это значит? Казалось бы, неправильное исключение будет тут же перехвачено! Однако тщательно исследуйте блок catch, и вы поймете, что, прежде чем искать исключение типа xZero, в нем ищется исключение типа xTooSmall. А поскольку возник объект класса xZero, который также является объектом класса xTooSmall, то он перехватывается обработчиком исключения xTooSmall. Будучи уже обработанным, это исключение не передается другим обработчикам, так что обработчик исключений типа xZero никогда не вызывается.

Решение этой проблемы лежит в тщательном упорядочении обработчиков таким образом, чтобы самые специфические из них стояли в начале, а более общие следовали за ними. В данном примере для решения проблемы достаточно поменять местами два обработчика — xZero и xTooSmall.

 

 

Данные в классах исключений и присвоение имен объектам исключений

 

Часто для того, чтобы программа могла отреагировать должным образом на ошибку, полезно знать несколько больше, чем просто тип возникшего исключения. Классы исключений — это такие же классы, как и любые другие. Вы абсолютно свободно можете добавлять любые данные в эти классы, инициализировать их с помощью конструктора и считывать их значения в любое время, как показано в листинге 20.4.

Листинг 20.4. возвращение данных из объекта исключения

1: #include <iostream.h>

2:

3: const int DefaultSize = 10;

4:

5: class Array

6: {

7: public:

8: // конструкторы

9: Array(int itsSize = DefaultSize);

10: Array(const Array &rhs);

11: ~Array() { delete [] pType;}

12:

13: // операторы

14: Array& operator=(const Array&);

15: int& operator[](int offSet);

16: const int& operator[](int offSet) const;

17:

18: // методы доступа

19: int GetitsSize() const { return itsSize; }

20:

21: // функция-друг

22: friend ostream& operator<< (ostream&, const Array&);

23:

24: // определение классов исключений

25: class xBoundary { };

26: class xSize

27: {

28: public:

29: xSize(int size):itsSize(size) { }

30: ~xSize(){ }

31: int GetSize() { return itsSize; }

32: private:

33: int itsSize;

34: };

35:

36: class xTooBig : public xSize

37: {

38: public:

39: xTooBig(int size):xSize(size){ }

40: };

41:

42: class xTooSmall : public xSize

43: {

44: public:

45: xTooSmall(int size):xSize(size){ }

46: };

47:

48: class xZero : public xTooSmall

49: {

50: public:

51: xZero(int size):xTooSmall(size){ }

52: };

53:

54: class xNegative : public xSize

55: {

56: public:

57: xNegative(int size):xSize(size){ }

58: };

59:

60: private:

61: int *pType;

62: int itsSize;

63: };

64:

65:

66: Array::Array(int size):

67: itsSize(size)

68: {

69: if (size == 0)

70: throw xZero(size);

71: if (size > 30000)

72: throw xTooBig(size);

73: if (size <1)

74: throw xNegative(size);

75: if (size < 10)

76: throw xTooSnall(size);

77:

78: pType = new int[size];

79: for (int i = 0; i<size; i++)

80: pType[i] = 0;

81: }

82:

83:

84: int& Array::operator[] (int offSet)

85: {

86: int size = GetitsSize();

87: if (offSet >= 0 && offSet < GetitsSize())

88: return pType[offSet];

89: throw xBoundary();

90: return pType[0];

91: }

92:

93: const int&Array::operator[] (int offSet) const

94: {

95: int size = GetitsSize();

96: if (offSet >= 0 && offSet < GetitsSize())

97: return pType[offSet];

98: throw xBoundary();

99: return pType[0];

100: }

101:

102: int main()

103: {

104:

105: try

106: {

107: Array intArray(9);

108: for (int j = 0; j< 100; j++)

109: {

110: intArray[j] = j;

111: cout << "intArray[" << j << "] okay..." << endl;

112: }

113: }

114: catch (Array::xBoundary)

115: {

116: cout << "Unable to process your input!\n";

117: }

118: catch(Array::xZero theException)

119: {

120: cout << "You asked for an Array of zero objectsl " << endl;

121: cout << "Received " << theExesptiQn,GatSize() << endl;

122: }

123: catch (Array:;xTooBig theException)

124: {

125: cout << "This Array is too big,,, " << endl;

126: cout << "Received " << theException,GetSize() << endl;

127: }

128: catch (Array;:xTooSmall theException)

129: {

130: cout << "This Array is too small... " << endl;

131: cout << "Received " << theException.GetSize() << endl;

132: }

133: catch (...)

134: {

135: cout << "Something went wrong, but I've no idea what!\n";

136: }

137: cout << "Done.\n";

138: return 0;

139: }

 

Результат:

This array is too small...

Received 9

Done.

 

Анализ: Объявление класса xSize было изменено таким образом, чтобы включить в него переменную-член itsSize (строкаЗЗ) и функцию-член GetSize() (строка 31). Кроме того, был добавлен конструктор, который принимает целое число и инициализирует переменную-член, как показано в строке 29.

Производные классы объявляют конструктор, который лишь инициализирует базовый класс. При этом никакие другие функции объявлены не были (частично из экономии места в листинге).

Операторы catch в строках 114-136 изменены таким образом, чтобы создавать именованный объект исключения (thoException), который используется в теле блока catch для доступа к данным, сохраняемым в переменной-члене itsSize.

 

Примечание: При работе с исключениями следует помнить об их сути: если уж оно возникло, значит, что-то не в порядке с распределением ресурсов, и обработку этого исключения нужно записать таким образом, чтобы вновь не создать ту же проблему. Следовательно, если вы создаете исключение OutOfMemory, то не стоит а конструкторе этого класса пытаться выделить память для какого-либо объекта.

 

Весьма утомительно писать вручную все эти конструкции с операторами oatch, каждый из которых должен выводить свое сообщение. Тем более, что при увеличении объема программы стремительно возрастает вероятность возникновения в ней ошибок. Лучше переложить эту работу на объект исключения, который сам должен определять тип исключения и выбирать соответствующее сообщение. В листинге 20.5 для решения этой проблемы использован подход, который в большей степени отвечает принципам объектно-ориентированного программирования. В классах исключений применяются виртуальные функции, обеспечивающие полиморфизм объекта исключения.


Дата добавления: 2019-02-12; просмотров: 254; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!