Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lektsii_OOP.doc
Скачиваний:
4
Добавлен:
01.03.2025
Размер:
4 Mб
Скачать

7. Примеры перегрузки некоторых операций

7.1. Перегрузка операции [ ]

Пусть определен объект

String s(“Еденица”);

Заметив ошибку, попытаемся ее исправить

s[2] = ’и’; // ошибка: операция [ ] в классе String не определена

Действительно, объект может иметь несколько полей данных типа «массив» и компилятору неизвестно, к какому массиву мы хотим применить операцию [ ]. Следовательно, ее надо определить. Для этого переопределим функцию Index( ) (см. п.4), как операцию [ ].

char & String:: operator [ ](int i)

{if (i < 0 || i >= len)

{cout << ”\n Индекс за пределами строки”; return line[0];}

return line[i];

}

В этом случае можно записать оператор

s[2] = ’и’;

Заметим (как и в пояснении к функции Index( ) из п.4), что если возвращаемое значение задать просто как char, то присвоение s[2] = ’и’ выполнить было бы нельзя, так как никакому конкретному значению что-либо другое присвоить невозможно. char & означает, что возвращается имя элемента – ссылка на его место в памяти. Это позволяет и использовать значение символа в операторах и операциях (выводить, сравнивать,…), и менять его значение.

7.2. Перегрузка операции ()

Если объект – матрица, то для обращения к ее элементам нельзя перегрузить [ ][ ]. В этом случае можно использовать перегрузку операции ( ).

class Matrix{int **a, m, n;

public:

Matrix(int, int, int t = 0);

~Matrix( );

void Show( );

int& operator( ) (int, int);

};

Matrix:: Matrix(int mm, int nn, int t) // mm – строк, nn – столбцов, t != 0 – генерация случайных чисел

{m = mm; n = nn; int i, j;

a = new int *[m];

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

a[i] = new int [n];

if(t)

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

for(j = 0; j < n; j++) a[i][j] = random(50);

}

void Matrix:: Show()

{int i, j;

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

{ cout << "\n";

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

{cout.width(5); // число позиций для вывода

cout << a[i][j];} // или printf("%5d", a[i][j]);

}

};

int& Matrix:: operator()(int i, int j)

{if (i < 0 || i >= m || j < 0 || j >= n)

{cout << "\n Значения индексов недопустимы. Выход.";exit(1);}

return a[i][j];

}

Пример использования.

void main( )

{randomize( );

Matrix B(4, 4, 1);

B.Show( );

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

B(i, i) = 0; // записать нули на главную диагональ

cout << "\nB:" << endl;

B.Show( );

...

}

Замечание. Операция ( ) – единственная, которая может иметь произвольное количество аргументов.

7.3. Перегрузка операции =

Если объект использует динамическую область, то для него надо перегрузить операцию ‘= ‘– присвоение. Рассмотрим почему.

Пусть заданы 2 объекта

String s1, s2(“ФПМК”);

...

s1 = s2;

Картина присвоения напоминает ситуацию с инициализацией:

до присвоения

s1 = s2;

после присвоения:

При выполнении операции s1 = s2 для полей line и len выполнится предопределенная операция копирования s2.line = s1.line, s2.len = s1.len.

Это недопустимо по следующим причинам:

  1. память в 80 байтов у объекта s1 будет «брошена» (считаться занятой);

  2. объекты s1 и s2 будут использовать одну и ту же динамическую память по указателю поля line, что приведет к тому, что любое изменение в поле line объекта s1 приведет к изменению line объекта s2 и наоборот;

  3. при выходе из программы деструктор будет пытаться дважды освободить одну и ту же динамическую память: это фатальная ошибка.

В классах, где используется динамическая память, операция ‘=’ обязательно перегружается.

Запишем пример перегрузки операции = для класса String.

String String:: operator =(String s)

{ if (this != &s) // на случай присвоения s = s

{ delete [ ] line;

line = new char [(len = s.len) + 1];

strcpy(line, s.line);

}

return *this;

}

Теперь присвоение s1 = s2 будет выполняться грамотно.

7.4. Перегрузки операций + и +=

При рассмотрении вопроса о перегрузке операций в абстрактных классах в п.6 был рассмотрен пример перегрузки операции ‘+=’, меняющей первый операнд, то есть *this. В классе String определим операцию +, которая не меняет ни первого операнда, ни второго, как это принято при сложении базовых типов данных. Например, когда мы выполняем операцию a + b, то результат не записывается ни в a, ни в b, если мы не выполним соответствующего присвоения (например, a = a + b, b = a + b, c = a + b).

Определение операции + может быть задано таким образом:

String String:: operator + (String &s)

{String z(len + s.len + 1); // определим локальную строку суммарной длины

strcpy(z.line, line); // перепишем в нее строку первого операнда

strcat(z.line, s.line) ; // прибавим строку второго операнда

z.len = strlen(z.line); // сформируем длину результата

return z;// работает конструктор копирования результата, затем деструктор разрушает локальный объект z

}

Пример использования операции для сложения 3-х строк.

void main()

{String s1(“Объект ”), s2(“класса “), s3(“ String”);

String s4 = s1 + s2 + s3; // работают 2 операции ‘+’ и конструктор копирования

s4.Print(); // вывод «Объект класса String»

}

7.5. Перегрузка операции ++

Одноместная операция ‘++’ перегружается только в префиксной форме (++i).

Приведем пример ее перегрузки для класса String: операция увеличивает коды символов на 1.

String String:: operator ++( )

{for(int i = 0; i < len; i++) line[i]++;

return *this;

}

Использование:

void main( )

{String d{“12345*678”);

++d;

d.Print( ); // d = ”234567+789”

}

Аналогично перегружается операция -- .

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]