4 - Перегрузка операторов и операторы преобразования типов в C++

Лабораторная работа 4 для студентов курса “Программирование на основе классов и шаблонов” 2 семестра кафедры ИУ5 МГТУ им Н.Э. Баумана.

Содержание

Цель работы

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

В ходе выполнения лабораторной работы студент осваивает:

Начало работы

Зайдите в свою локальную директорию с репозиторием для выполнения лабораторных работ. Заберите ветку с соответствующей лабораторной работой из общего репозитория:

git pull upstream

или

git pull upstream lab_4

Переключитесь на ветку с текущей лабораторной работой:

git checkout lab_4

Свяжите ветку локального репозитория с вашим удаленным репозиторием:

git push --set-upstream origin lab_4

Задание

Лабораторная работа состоит из двух независимых заданий:

Часть 1. Основной проект (обязательный):

I. Создать класс Fraction для выполнения арифметических операций над обыкновенными дробями.

II. Разработать конструкторы

III. Перегрузить операции потокового ввода дроби с клавиатуры и вывода ее на экран монитора. При вводе и выводе дроби обеспечить автоматическое сокращение дроби и корректный вывод знака.

IV. Создать многофайловый проект и отладить программу, использующую класс Fraction, состоящую из первых пяти логических фрагментов программы (ввод, конструкторы, копирование, операции с дробями, операции с целыми),
приведённой в Приложении 1.

V. Дополнить класс функциями-членами класса и функциями-друзьями класса, которые необходимы для выполнения программы из Приложения 1.

VI. Выполнить программу из Приложения 1 и сравнить результаты с тестовым примером.

предупреждение
Класс Fraction необходимо упаковать в самостоятельную статическую библиотеку.

Часть 2. Дополнительный проект (опциональный / повышенный уровень):

Целью является демонстрация альтернативного подхода к перегрузке операторов без использования дружественных функций.

Необходимо:

  1. Разработать необходимые конструкторы для преобразования простых типов (int, double) к классу Fraction.

  2. Реализовать альтернативный вариант класса Fraction, в котором:

    • отсутствуют дружественные операторы для работы с простыми типами;
    • все операции выполняются за счёт конструкторов преобразования и операторов преобразования типов;
    • сравнить оба подхода (кратко опишите различия между двумя подходами: необходимость использования дружественных функций; удобство использования;особенности неявных преобразований типов).

Программа из Приложения 1 должна корректно работать в обоих вариантах реализации класса, несмотря на различие механизмов перегрузки.

Указания по выполнению лабораторной работы

Часть 1.

Создание класса.

В данной лабораторной работе необходимо создать класс для работы с обыкновенными дробями. Все операции, которые должны выполняться с дробями, включены в программу в Приложении 1.

Числитель и знаменатель дроби имеют тип int.

Дроби вводятся как строка, имеющая вид:

Значения представленных выше дробей на экране при выводе должны иметь вид:

-2 1/3,  8,  6.
3/4,  -3,  -1 1/3.

предупреждение

Создание конструкторов.

Для инициализации объектов разрабатываемого класса обыкновенных дробей предусмотреть соответствующие конструкторы (с одним аргументом типа char* и с двумя аргументами типа int, которые имеют значения по умолчанию).

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

Для работы с дробями необходимо:

  1. Перегрузить операции +, += для сложения дробей и дроби_и_целого в любых сочетаниях (дробь+целое, целое+дробь, дробь+дробь).
  2. Перегрузить операции +, += для сложения дроби и double в любых сочетаниях (дробь+double, double+дробь). Преобразование double->дробь должно выполняться с точностью до kNumberDecimalPlaces десятичных знаков после запятой, где kNumberDecimalPlaces - целочисленная константа, задаваемая пользователем. Задайте значение по умолчанию kNumberDecimalPlaces = 4.

осторожно

Для разбора double запрещено использовать тип string.

При перегрузке операций использовать функции-члены класса, а где это невозможно, то функции-друзья класса.

Обратите внимание: операция вида int + Fraction не может быть реализована как метод класса.

Часть 2.

Вторая часть лабораторной работы необходима для разработки операций преобразований типов.

Для этого необходимо создать соответствующие конструкторы или определить методы преобразования типов. Для выполнения Части 2 необходимо реализовать вторую версию класса Fraction (в отдельном проекте или модуле), в которой:

Контрольные вопросы

  1. Как работает перегрузка операторов?

  2. Что значит продолжение жизни временного объекта? Как реализовывается?

  3. Зачем нужны дружественные методы?

  4. Почему в части 2 можно удалить дружественные методы?

  5. В чём отличие конструктора преобразования от оператора преобразования типов?

Приложение 1

#include <iostream>
#include "fraction.h"

int main() {
    Fraction z;
    std::cout << "Введите дробь: ";
    std::cin >> z;
    std::cout << "1. Ввод дроби с клавиатуры\n";
    std::cout << "z = " << z << std::endl;

    Fraction fr1(10, 14);
    Fraction fr2;
    Fraction fr3("-1 4/8");

    std::cout << "2. Проверка конструкторов\n";
    std::cout << "fr1 = " << fr1 << std::endl;
    std::cout << "fr2 = " << fr2 << std::endl;
    std::cout << "fr3 = " << fr3 << std::endl;


    Fraction x(z);
    std::cout << "3. Проверка копирующего конструктора\n";
    std::cout << "x = " << x << std::endl;

    std::cout << "4. Арифметические операции (дробь + дробь)" << std::endl;
    Fraction y = x + fr1;
    std::cout << "y = x + fr1 = " << y << std::endl;

    y += fr3;
    std::cout << "y += fr3 -> " << y << std::endl;

    std::cout << "5. Арифметика с целыми числами" << std::endl;
    int i = 5;
    y = x + i;
    std::cout << "y = x + i = " << y << std::endl;

    y = i + x;
    std::cout << "y = i + x = " << y << std::endl;

    y += i;
    std::cout << "y += i -> " << y << std::endl;

    std::cout << "6. Арифметика с double" << std::endl;
    double d = -1.25;
    Fraction f = d;  // Преобразование double -> Fraction (используется в части 2)
    std::cout << "f = " << f << std::endl;

    y = x + d;
    std::cout << "y = x + d = " << y << std::endl;

    y = d + x;
    std::cout << "y = d + x = " << y << std::endl;

    y += d;
    std::cout << "y += d -> " << y << std::endl;

    y += d + i;
    std::cout << "y += d + i -> " << y << std::endl;

    return 0;
}