§ 3. Перегрузка операций
Упражнения
1. Для программы из примера 3.5 выполните следующее:
- Дополните описание класса перегрузкой операторов ввода и вывода, приведенное в примерах 3.7 и 3.9.
- Измените функции для перегрузки операторов сравнения так, чтобы они были дружественными.
- Как будет реагировать программа, если использовать знак «<» для сравнения длин векторов? Почему?
- Перегрузите операции «<» и «!=».
- Перегрузите оператор «*» еще раз, считая, что он используется и для нахождения скалярного произведения двух векторов [1].
[1] Скалярным произведением двух векторов и является число .
2. Для программы из примера 3.6 выполните следующее:
- Реализуйте многофайловый проект, разделите объявление и определение класса. Создайте файлы Matrix.h и Matrix.cpp.
- Дополните описание класса перегрузкой операторов ввода и вывода, приведенное в примерах 3.8 и 3.10.
- Измените функции для перегрузки операторов так, чтобы они были дружественными.
- Перегрузите операцию «==», которая будет возвращать true, в том случае, если матрицы имеют одинаковые размеры и false в противном случае.
- * Перегрузите оператор «*» еще раз, считая, что он используется и для нахождения произведения матриц[1]
[1] О том, как умножать матрицы, можно почитать здесь: https://www.webmath.ru/poleznoe/formules_6_6.php.
- Продемонстрируйте работу методов и операторов описанного класса.
3. Измените описание класса Parallelepiped (задание 4, §2), добавив перегрузку операторов сравнения параллелепипедов по объему.
4. Добавьте в класс Rect (задание 6, §2) перегрузку операций «+» для получения наименьшего прямоугольника, содержащего два заданных прямоугольника, и «*» — для получения прямоугольника, являющегося общей частью (пересечением) двух прямоугольников.
5. Создать класс Drob. Конструктор принимает два числа: числитель и знаменатель дроби. Перегрузить операции: сложение, умножение, деление, вычитание. Реализовать методы: сокращение (использовать private функцию для нахождения НОД по алгоритму Евклида), перевод обыкновенной дроби в десятичную. Продемонстрировать работу всех функций класса и перегруженных операций на примерах.
6. Создать базовый класс Progressii и ее наследников — арифметическую и геометрическую прогрессии. Реализовать методы: n-ый член прогрессии, проверка прогрессии на убывание. Перегрузить операции: «+» (первый операнд — переменная типа прогрессии, второй — число (количество элементов)) для вычисления суммы арифметической прогрессии; «*» — аналогично для вычисления суммы геометрической прогрессии. Продемонстрировать работу всех функций класса и перегруженных операций на примерах.
7. Описать класс Polinom для работы с многочленами. Полями класса является степень многочлена и массив коэффициентов. Перегрузить операции «+», «-», «*», а также ввод и вывод многочлена. Реализовать метод вычисления значения многочлена для заданного значения переменной[1]. *Используя метод двоичного деления, найти корень многочлена на заданном промежутке (корень должен быть на этом промежутке единственным).
[1] Рекомендуется использовать для вычисления значения многочлена схему Горнера — https://intuit.ru/studies/professional_retraining/941/courses/67/lecture/1966?page=2
8*. Описать класс BigNumber для работы с «большими» числами (числа, которые не помещаются в стандартные типы). Перегрузите операции «+», «-», «*», сравнения, ввода и вывода.
Пример описания некоторых членов класса:
///Класс "большое число", описывает способ хранения большого числа и сложение
class BigNumber
{
private:
vector < int > cifr;
///нормализация числа моделирует перенос в следующий разряд, если цифра > 10
void norm();
public:
///Конструктор по умолчанию ("пустое" число)
BigNumber() {};
///Конструктор, конвертирует строку в большое число
BigNumber(string str)
BigNumber operator + (const BigNumber &);
friend ostream & operator << (ostream &, const BigNumber &);
};
BigNumber::BigNumber(string str)
{
///Записываем цифры с конца строки
for (int i = str.size() - 1; i >= 0; i --)
cifr.push_back(str[i] - '0');
}
///Оператор +, выполняет сложение больших чисел
BigNumber BigNumber::operator + (const BigNumber &num)
{
BigNumber res;
int r1 = min(cifr.size(), num.cifr.size());
res.cifr.resize(r1);
/// сложение цифр
for (int i = 0; i < r1; i++)
res.cifr[i] = cifr[i] + num.cifr[i];
///если в одном из чисел цифры закончились
for (int i = r1; i < cifr.size(); i++)
res.cifr.push_back(cifr[i]);
for (int i = r1; i < num.cifr.size(); i++)
res.cifr.push_back(num.cifr[i]);
res.norm();
return res;
}
void BigNumber::norm()
{
if (cifr.size() > 1) {
for (int i = 0; i < cifr.size()-1; i++) {
cifr[i + 1] += cifr[i] / 10;
cifr[i] = cifr[i] % 10;
}
if (cifr[cifr.size() - 1] >= 10) {
int t = cifr[cifr.size() - 1] / 10;
cifr[cifr.size() - 1] = cifr[cifr.size() - 1] % 10;
cifr.resize(cifr.size() + 1);
cifr[cifr.size()-1] = t;
}
}
}
///Перегрузка оператора << для вывода
ostream & operator << (ostream &cout_bn, const BigNumber &num)
{
for (int i = num.cifr.size() - 1; i >= 0; i--)
cout_bn << num.cifr[i];
}
Пример использования:
int main() {
BigNumber n1("9999999999999999");
BigNumber n2("1");
cout << n1 << endl;
cout << n2 << endl;
BigNumber n3 = n1 + n2;
cout << n3 << endl;
return 0;