Предусловия и постусловия описывают свойства отдельных программ. Но экземпляры класса обладают также глобальными свойствами. Их принято называть инвариантами класса
Для многих классов существует ряд условий, которые всегда должны выполняться при завершении работы с функцией-членом класса. Эти обязательные условия также относятся к инвариантам класса.
Может быть весьма полезным определение метода Invariants(), который возвращает значение TRUE только в том случае, если каждое из этих условий является истинным. Затем можно вставить макрос ASSERT(Invariants()) в начале и в конце каждого метода класса. В качестве исключения следует помнить, что метод Invariants() не возвращает TRUE до вызова конструктора и после выполнения деструктора.
#define DEBUG
#define SHOW_INVARIANTS
#include <iostream>
#include <string >
#ifndef DEBUG
#define ASSERT(x)
#else
#define ASSERT(x)
if (! (x)) { cout<< "ERROR!!Assert "<< x << " failed\n";
cout<< " on line " << __LINE__ << "\n";
cout<< " in file " << FILE << "\n";
}
#endif
Class String
|
|
{ public:
String() // конструкторы
{ itsString = newchar[1]; //конструкторпоумолчаниюсоздаетстрокунулевойдлины
itsString[0] = '\0';
itsLen=0;
ASSERT(Invariants());
}
String(const char *constcString) // инициализацияобъектастрокой
{ itsLen = strlen(cString);
itsString = new char[itsLen+1];
for (inti = 0; i<itsLen; i++)
itsString[i] = cString[i];
itsString[itsLen] ='\0';
ASSERT(Invariants());
}
String(const String &rhs) //конструкторкопирования
{ itsLen=rhs.GetLen();
itsString = new char[itsLen+1];
for (inti = 0; i<itsLen;i++)
itsString[i] = rhs[i];
itsString[itsLen] = '\0';
ASSERT(Invariants());
}
~String() //деструктор освобождает выделенную память
{ ASSERT(Invariants());
delete [] itsString;
itsLen = 0;
}
private:
String (intlen) //privateконструктор, используетсятолько для создания
{ itsString = newchar[len+1]; // новой строки требуемого размера.
for (inti = 0; i<=len; i++) // При этом вставляется концевой \0
itsString[i] = '\0';
itsLen=len;
ASSERT(Invariants());
}
char * itsString;
intitsLen // целочисленнаяпеременнаяitsLen;
public:
char& operator [] (int offset) //неконстантныйоператор []
{ ASSERT(Invariants());
if (offset >itsLen)
{ ASSERT(Invariants()); //недопустимыйаргумент - возврат
returnitsString[itsLen-1];// последнегосимволастроки
}
else
{
ASSERT(Invariants());
returnitsString[offset];
}
}
char operator[] (int offset)const//константныйоператор []
{ ASSERT(Invariants());
charretVal;
if (offset >itsLen)
retVal = itsString[itsLen-1];
else
retVal = itsString[offset];
ASSERT(Invariants());
returnretVal;
}
String & operator= (const String &rhs) //перегрузкаоперации =
{ ASSERT(Invariants()); // операторвыполняетсравнение
|
|
if (this == &rhs)
return *this;
delete [] itsString; //освобождает занятуюпамять,
itsLen = rhs.GetLen(); //затем копирует строку и ее размер
itsString = new char[itsLen+1];
for (inti = 0; i<itsLen;i++)
itsString[i] = rhs[i];
itsString[itsLen] = '\0';
ASSERT(Invariants());
return *this;
}
intGetLen()const{ return itsLen; } //методыкласса
constchar * GetString() const { return itsString; }
BoolInvariants() const
{ #ifdefSHOW_INVARIANTS
cout<< "Invariants Tested";
#endif
return ((itsLen&&itsString) || (!itsLen&&!itsString));
};
};