Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции / LECS14.DOC
Скачиваний:
43
Добавлен:
16.04.2013
Размер:
89.09 Кб
Скачать

Перегруженные операторы ввода-вывода « и »

Сохраняя дух ООП, важно перегрузить оператор «, чтобы выводить пользователь­ские типы, так же как и собственные. Оператор « имеет два аргумента: ostream& и АТД, и должен создавать ostream&. Используется ссылка на поток и возвращается ссылка на поток (вне зависимости от того, что перегружается — « или »), потому, что мы не хотим копировать объект потока. Напишем эти функции для типа rational.

В файле rational.cpp

class rational{

public:

friend ostream& operator«(ostream& out, rational x) ;

friend istream& operator»(istream& in, rational& x) ;

. . . . .

private:

long a, q;

};

ostream& operator«(ostream& out, rational x)

{

return (out « x.a « " / " « x.q « '\t');

}

Перегрузка оператора » для вывода пользовательского типа обычно выглядит так:

istream& operator»(istream& р, пользовательский_тип& x)

Если функции необходим доступ к закрытым членам x, ее надо сделать дружественной к этому классу. Ключевой момент здесь — сделать х параметром-ссылкой, чтобы его значение можно было изменять. Для этого в классе rational необходимо поместить объявление friend для этого оператора и обеспечить определение его функции:

istream& operator»(istream& in, rational& x)

{

return (in » x.a » x.q);

}

Перегрузка оператора ( ) для индексирования

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

Оператор вызова функции () перегружается как нестатическая функция-член. Он может быть перегружен для различных сигнатур. Он часто используется в oпeрациях итератора (см. упражнения с 12, стр. 222 по 14, стр. 223) или в тех операциях, где нужны множественные индексы (см. упражнение 8, на стр. 228, для операции с подстроками).

В файле matrix3.cpp

//Тип для динамической матрицы

class matrix {

public:

matrix(int с, int r);

~matrix();

doubles operator()(int i, int j);

matrix& operator=(const matrix& m);

matrix& operator+= (matrix& m);

private:

int c_size, r_size;

double **p;

};

matrix::matrix(int c, int r) : c_size(c), r_size(r)

{

p = new double*[c] ;

assert(p != 0);

for (int i = 0; i <c; ++i){

p[i] = new double[r];

assert(p[i] i= 0);

}

}

matrix:: ~matrix()

{

for (int i = 0; i < c_size; ++i)

delete [] p[i] ;

delete [] p;

}

inline double& matrix::operator()(int i, int j)

{

assert ( i >= 0 && i < c_size && j >= 0 && j < r_size) ;

return p[i][j];

}

matrix& matrix::operator=(const matrix& m)

{

assert(m.c_size = = c_size && m.r_size = = r_size);

int i , j ;

for (i = 0; i < c_size; ++i)

for (j = 0; j < r_size; ++j)

p[i] [jl = m.p[i][j];

return (*this) ;

}

matrix& matrix::operator+=(matrix& m)

{

assert(m.c_size == c_size && m.r_size == r_size);

int i , j ;

for (i=0; i<c_size; ++i)

for (j=0; j,r_size; i++)

p[i][j]+=m.p.[i][j];

return *this;

}

Разработка класса matrix

• inline double& matrix::operator()(int i, int j)

{

assert( i >= 0 && i < c_size && j >= 0 && j < r_size) ;

return p[i] [j] ;

}

Данная функция-член дает удобную многоаргументную нотацию для доступа к эле­ментам. Это приводит к тому, что в клиентском коде можно использовать выражения вида m (i, j ) для доступа к элементам матрицы. Отметьте, что индексы матрицы проверяются на нахождение в пределах границ с помощью утверждений.

• matrix& matrix::operator+=(matrix& m)

{

assert(m.c_size = = c_size && m.r_size = = r_size);

Для проверки аргументов функции-члена на предусловие используется макро про­верки утверждений. Присваиваемая матрица должна быть такого же размера, как и та, которой она присваивается. Этот код заменил инструкцию if-else, отвечаю­щую за выход по ошибке. Сравните с кодом, написанным для класса vect (см. раздел 6.5, -«Класс vect», на стр. 166).

• for (i = 0; i <. c_size; ++i)

for (j = 0; j < r_size; ++j)

p[i] [j]+= m.p[i][j];

Этот вложенный цикл прозрачен и эффективен. Почленное сложение выполнено без накладных расходов.

• return (*this) ;

Возвращаемый тип является ссылкой на matrix. Разыменовывая указатель this, мы получаем lvalue объекта matrix. Это обычный прием, позволяющий выполнять множественные (порторные) присваивания.

Обсуждение данной программы продолжается в упражнении 24 на стр. 226.

Соседние файлы в папке Лекции