Листинг 21.5. Использование метода lnvariаnts ()



1: #define DEBUG

2: #define SHOW_INVARIANTS

3: #include <iostream.h>

4: #include <string.h>

5:

6: #ifndef DEBUG

7: #define ASSERT(x)

8: #else

9: #define ASSERT(x)

10: if (! (x))

11: {

12: cout << "ERROR!! Assert " << #x << " failed\n";

13: cout << " on line " << __LINE__ << "\n";

14: cout << " in file " << FILE << "\n";

15: }

16: #endif

17:

18:

19: const int FALSE = 0;

20: const int TRUE = 1;

21: typedef int bool;

22:

23:

24: class String

25: {

26: public:

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

28: String();

29: String(const char *const);

30: String(const String &);

31: ~String();

32:

33: char & operator[](int offset);

34: char operator[](int offset) const;

35:

36: String & operator= (const String &);

37: int GetLen()const { return itsLen; }

38: const char * GetString() const { return itsString; }

39: bool Invariants() const;

40:

41: private:

42: String (int); // закрытый конструктор

43: char * itsString;

44: // беззнаковая целочисленная переменная itsLen;

45: int itsLen

46: };

47:

48: // стандартный конструктор создает строку нулевой длины

49: String::String()

50: {

51: itsString = new char[1];

52: itsString[0] = '\0';

53: itsLen=0;

54: ASSERT(Invariants());

55: }

56:

57: // закрытый (вспомогательный) конструктор, используется

58: // методами класса только для создания новой строки

59: // требуемого размера, При этом вставляется концевой нулевой символ.\

60: String::String(int len)

61: {

62: itsString = new char[len+1];

63: for (int i = 0; i<=len; i++)

64: itsString[i] = '\0';

65: itsLen=len;

66: ASSERT(Invariants());

67: }

68:

69: // Преобразует массив символов к типу String

70: String::String(const char * const cString)

71: {

72: itsLen = strlen(cString);

73: itsString = new char[itsLen+1];

74: for (int i = 0; i<itsLen; i++)

75: itsString[i] = cString[i];

76: itsString[itsLen] ='\0';

77: ASSERT(Invariants());

78: }

79:

80: // конструктор-копировщик

81: String::String (const String & rhs)

82: {

83: itsLen=rhs.GetLen();

84: itsString = new char[itsLen+1];

85: for (int i = 0; i<itsLen;i++)

86: itsString[i] = rhs[i];

87: itsString[itsLen] = '\0';

88: ASSERT(Invariants());

89: }

90:

91: // деструктор, освобождает выделенную память

92: String::~String ()

93: {

94: ASSERT(Invariants());

95: delete [] itsString;

96: itsLen = 0;

97: }

96:

99: // оператор выполняет сравнение, освобождает занятую

100: // память, а затем копирует строку и ее размер

101: String& String::operator=(const String & rhs)

102: {

103: ASSERT(Invariants());

104: if (this == &rhs)

105: return *this;

106: delete [] itsString;

107: itsLen=rhs,GetLen();

108: itsString = new char[itsLen+1];

109: for (int i = 0; i<itsLen;i++)

110: itsString[i] = rhs[i];

111: itsString[itsLen] = '\0';

112: ASSERT(Invariants());

113: return *this;

114: }

115:

116: // неконстантный оператор индексирования

117: char & String::operator[](int offset)

118: {

119: ASSERT(Invariants());

120: if (offset > itsLen)

121: {

122: ASSERT(Invariants());

123: return itsString[itsLen-1];

124: }

125: else

126: {

127: ASSERT(Invariants());

128: return itsString[offset];

129: }

130: }

131: // константный оператор индексирования

132: char String::operator[](int offset) const

133: {

134: ASSERT(Invariants());

135: char retVal;

136: if (offset > itsLen)

137: retVal = itsString[itsLen-1];

138: else

139: retVal = itsString[offset];

140: ASSERT(Invariants());

141: return retVal;

142: }

143: bool String::Invariants() const

144: {

145: #ifdef SHOW_INVARIANTS

146: cout << "Invariants Tested";

147: #endif

148: return ( (itsLen && itsString) ||

149: (!itsLen && !itsString) );

150: }

151: class Animal

152: {

153: public:

154: Animal():itsAge(1),itsName("John Q. Animal")

155: { ASSERT(Invariants());}

156: Animal(int, const String&);

157: ~Animal(){ }

158: int GetAge() { ASSERT(Invariants()); return itsAge;}

159: void SetAge(int Age)

160: {

161: ASSERT(Invariants());

162: itsAge = Age;

163: ASSERT(Invariants());

164: }

165: String& GetName()

166: {

167: ASSERT(Invariants());

168: return itsName;

169: }

170: void SetName(const String& name)

171: {

172: ASSERT(Invariants());

173: itsName = name;

174: ASSERT(Invariants());

175: }

176: bool Invariants();

177: private:

178: int itsAge;

179: String itsName;

180: };

181:

182: Animal::Animal(int age, const String& name):

183: itsAge(age),

184: itsName(name)

185: {

186: ASSERT(Invariants());

187: }

188:

189: bool Animal::Invariants()

190: {

191: #ifdef SHOW_INVARIANTS

192: cout << "Invariants Tested";

193: #endif

194: return (itsAge > 0 && itsName.GetLen());

195: }

196:

197: int main()

198: {

199: Animal sparky(5, "Sparky");

200: cout << "\n" << sparky.GetName().GetString() << " is ";

201: cout << sparky.GetAge() << " years old. ";

202: sparky.SetAge(8):

203: cout << "\n" << sparky.GetName(). GetString() << " is ";

204: cout << sparky.GetAge() << " years old. ";

205: return 0;

206: }

 

Результат:

String OK String OK String OK String OK String OK String OK String OK

String OK String OK Animal OK String OK Animal OK

Sparky is Animal OK 5 years old. Animal OK Animal OK

Animal OK Sparky is Animal OK 8 years old. String OK

 

Анализ: В строках 9—15 определяется макрос assert(). Если лексема DEBUG определена и макрос assert() возвратит в результате операции сравнения значение FALSE, будет выведено сообщение об ошибке.

В строке 39 объявляется функция-член Invariants() класса String, а ее определение занимает строки 143—150. Конструктор объявляется в строках 49—55, а в строке 54, после того как объект полностью построен, вызывается функция-член Invariants(), чтобы подтвердить правомочность этой конструкции.

Этот алгоритм повторен для других конструкторов, а для деструктора функция- член Invariants() вызывается только перед тем, как удалить объект. Остальные методы класса вызывают функцию Invariants() перед выполнением любого действия, а затем еще раз перед возвратом из функции. В этом проявляется отличие функций- членов от конструкторов и деструкторов: функции-члены всегда работают с реальными объектами и должны оставить их таковыми по завершению выполнения функции.

В строке 176 класс Animal объявляет собственный метод Invariants(), выполняемый в строках 189—195. Обратите внимание на строки 155, 158, 161 и 163: подставляемые функции также могут вызывать метод Invariants().

 


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

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






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