- •Введение. Принципы объектно-ориентированного программирования
- •Глава 1. Классы и объекты
- •1.1. Операция разрешения области видимости ::
- •1.2. Перечислимый тип
- •1.3. Модификатор const
- •1.4. Новый тип данных – ссылка &
- •Inline определение_функции
- •2. Определение класса. Сокрытие информации.
- •3. Объект.
- •4. Конструкторы и деструкторы
- •4.1.Назначение конструктора
- •4.2. Конструктор копирования
- •X::X(X&); // где X – имя класса
- •4.3. Деструктор
- •5. Неявный указатель this
- •6. Перегрузка операций
- •7. Примеры перегрузки некоторых операций
- •7.1. Перегрузка операции [ ]
- •7.2. Перегрузка операции ()
- •7.6. Перегрузка операции (тип)
- •8. Дружественность
- •Istream
- •10. Массивы объектов.
- •11. Функции- и классы-шаблоны
- •11.1 Функции-шаблоны (родовые функции)
- •11.2 Классы-шаблоны
- •12. Член-данные класса – объекты другого класса: агрегированные классы.
- •Глава 2. Наследование. Полиморфизм
- •1. Базовый и порожденный классы
- •2. Конструкторы порожденного класса
- •3. Стандартные преобразования при наследовании
- •4. Множественное наследование. Виртуальный базовый класс
- •4.1. Прямые базовые классы
- •4.2. Виртуальный базовый класс
- •5. Полиморфизм, раннее и позднее связывание, виртуальные функции
- •5.1 Раннее (статическое) и позднее (динамическое) связывание
- •5.2. Определение виртуальной функции
- •5.3. Чистая виртуальная функция и абстрактный класс
- •5.4. Правила определения виртуальных функций
- •5.5. Механизм позднего связывания
- •6. Библиотека fstream – работа с файлами
- •Глава 3. Библиотека стандартных шаблонов (бсш). Контейнеры
- •1. Контейнер. Структура бсш.
- •2. Контейнер Vector – динамический массив
- •Контейнер list – список
- •4. Контейнер Set – множество
- •Содержание
- •Глава 1. Классы и объекты
- •Глава 2. Наследование. Полиморфизм
- •Глава 3. Библиотека стандартных шаблонов (бсш). Контейнеры
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.
Это недопустимо по следующим причинам:
память в 80 байтов у объекта s1 будет «брошена» (считаться занятой);
объекты s1 и s2 будут использовать одну и ту же динамическую память по указателю поля line, что приведет к тому, что любое изменение в поле line объекта s1 приведет к изменению line объекта s2 и наоборот;
при выходе из программы деструктор будет пытаться дважды освободить одну и ту же динамическую память: это фатальная ошибка.
В классах, где используется динамическая память, операция ‘=’ обязательно перегружается.
Запишем пример перегрузки операции = для класса 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”
}
Аналогично перегружается операция -- .
