В C++ имеются объявления ссылок. Модификаторы такого типа создают именующие выражения (адреса переменной). Помните, lvalue обозначает значение месторасположения. Справа от выражения назначения именующее выражение (адрес переменной) автоматически разыменовывается. Слева от выражения назначения именующее выражение (адрес переменной) определяет, где должно храниться соответствующее значение. Как индексация, так и назначение используют эти свойства именующих выражений (адресов переменной). Для АТД необходимо определять такие выражения в том случае, если подходящие значения по умолчанию недоступны. Перепишем класс vect из раздела 6.5, расширив его функциональность применением перегрузки операторов.
Переделанный класс обладает несколькими усовершенствованиями, которые делают его более надежным и полезным. Добавляется конструктор, который преобразует обычный массив целых чисел в безопасный. Это делается для того, чтобы позволить нам разрабатывать код, использующий безопасные массивы, а затем преобразовывать тот же код для эффективного использования обычных массивов. Public член-данные ub заменяется на функцию-член. Это предотвращает пользователя от ошибки в программе при неосторожной модификации члена. В заключение, перегружается оператор индексации [ ], заменяя функцию-член element.
//Тип безопасного массива vect с перегрузкой []
class vect
{private:
int* p; //базовый указатель
int size; //число элементов
public:
//конструкторы и деструкторы
vect(); //создает массив из 10 элементов
vect(int п); //создает массив из п элементов
vect(const vect& v); //инициализируется vect
vect(const int a[], int n);//инициализируется массивом
~vect() { delete [] p} ;
//прочие функции-члены
int ub(){return (size -1);} //проверка верхней границы
int& operator[](int i); //элемент, проверяемый на
//выход за пределы
vect& operator=(const vect& v); //перегруженное присвоение
vect operator+(const vect& v); //перегруженное сложение
};
Добавляются два вспомогательных конструктора:
vect::vect(const int а[],int n) //преобразует обычный массив
{if (n <= 0)
{
cerr<<"illegal vect size: "<<
exit(l) ;
}
size = n;
p = new int[size]; for (int i = 0; i < size; ++i)
p[i] = a[i];
}
vect::vect(const vect& v) //конструктор копии
{size = v.size;
p = new int[size];
for (int i = 0; i < size; ++i) p[i] = v.p[i] ;
}
Перегруженный оператор индексации берет целый аргумент и проверяет, находится ли это значение в пределах диапазона. Если да, он использует это значение для того, чтобы возвратить адрес индексированного элемента.
intS vect::operator [](int i)
{if (i < 0 || i > (size - 1)) {
cerr<<"illegal vect index: "<<
exit(l) ;
}
return (p[i]);
}
Перегруженный оператор индексации имеет возвращаемый тип и один параметр. Он должен быть нестатической функцией-членом. Хорошим стилем будет поддержание непротиворечивости между значением оператора индексации [ ], который определяется пользователем, и стандартным его значением. Таким образом, наиболее общий прототип функции:
имякласса& operator[] (целостный тип);
В таких функциях возвращается значение ссылки, которое может использоваться с любой стороны выражения назначения.
Когда назначение не перегружено, оно определяется по умолчанию с семантикой, представляющей собой присвоение значения. Это иногда называется семантикой “поверхностного копирования” и не всегда допустимо (см. главу 6). Удостовериться в том, что семантика по умолчанию правильна входит в обязанности поставщика класса. Если нет, как это произошло в нашем случае с vect, поставщик класса должен перегрузить конструкцию с правильной семантикой. Возможно также перегрузить оператор назначения с обработкой сигналов ошибочного поведения.
В следующем примере функция-член перегружает назначение для класса vect:
vectS vect::operator=(const vectS v)
{int s = (size < v.size) ? size : v.size;
if (v.size != size)
cerr<<"copying different size arrays "
<<<" and "<<
for (int i = 0; i < s; ++i) p[i] = v.p[i] ;
return (*this) ;
}
Похожие записи
No user прокомментировали сообщение
Оставить комментарий