#import "template.typ": *

#import "@preview/codelst:2.0.1": sourcecode, sourcefile

#import "diagrams/main.typ" as main_algo
#import "diagrams/user_input.typ" as input_algo
#import "diagrams/fill_matrix.typ" as fill_algo
#import "diagrams/count_values.typ" as count_algo

// Take a look at the file `template.typ` in the file panel
// to customize this template and discover how it works.
#show: project.with(
  title: "Объектно-ориентированное программирование. КМ-4. Более сложные элементы программирования.",
  authors: (
    "<NAME>",
  ),
)

#show figure: set block(breakable: true)

#outline()

= Задание
Работа выполняется по заданию из Семинара 3. Написать программу произведения матрицы на вектор.

== Комментарии

- Полный код программы находится в репозитории https://github.com/yan-aint-nickname/uni см.директорию: `oop-matrix-mul-cli`

- Для компиляции я использовал https://ziglang.org/
- Библиотека для тестирования https://github.com/sheredom/utest.h/

- Для дальнейшей работы мне необходимо сделать допущение для векторов, столбцовых и строковых матриц:

/ $n$ : - кол-во строк/столбцов вектора
$ZZ^n tilde.equiv ZZ^(n times 1) tilde.equiv ZZ^(1 times n)$\

Алгоритм перемножения матрицы на вектор:
$
mat(
  a_(0 0), a_(0 1), ..., a_(0 n);
  a_(1 0), a_(1 1), ..., a_(1 n);
  dots.v, dots.v, dots.down, dots.v;
  a_(m 0), a_(m 1), ..., a_(m n);
) times vec(b_0, b_1, dots.v, b_n) = vec(
  c_0 = a_(0 0) dot.op b_0 + a_(0 1) dot.op b_1 + ... + a_(0 n) dot.op b_n,
  c_1 = a_(1 0) dot.op b_0 + a_(1 1) dot.op b_1 + ... + a_(1 n) dot.op b_n,
  dots.v,
  c_n = a_(m 0) dot.op b_0 + a_(m 1) dot.op b_1 + ... + a_(m n) dot.op b_n)\
  c_i = sum^n_(k=0)a_(i k)b_k
$


= Код программы

== Заголовочный файл

#figure(
  caption: "Заголовочный файл tool.hh",
  sourcefile(
    file: "tool.hh",
    read("tool.hh"),
  )
)

== Реализация

#figure(
  caption: "Релазиация методов, алгоритма tool.cc",
  sourcefile(
    file: "tool.cc",
    read("tool.cc"),
  )
)

#figure(
  caption: "Точка входа программы main.cc",
  sourcefile(
    file: "main.cc",
    read("main.cc"),
  )
)

#pagebreak()
== Модульное тестирование

#figure(
  caption: "Модульное тестирования с использованием библиотеки utest.h",
  sourcefile(
    file: "tool_test.cc",
    read("tool_test.cc"),
  )
)

#pagebreak()
= Ответы на вопросы

1. Что такое дружественная функция? В чем состоит выигрыш от применения дружественных функций?

Дружественная функция в C++ - это функция, которая не является членом класса, но имеет возможность доступа к приватным и защищенным членам класса. Она объявляется с помощью ключевого слова `friend`. Дружественные функции не входят в область видимости класса, но они могут получать доступ к его приватным и защищенным членам. Это может быть особенно полезно в ситуациях, когда необходимо выполнить операции над данными класса, которые логически не принадлежат самому классу.

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

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

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

Когда использовать конструктор копирования:
- Если при копировании полей необходимо изменять содержимое хотя бы некоторых из них
- Если класс содержит хотя бы одно динамическое поле

Конструктор копирования вызывается в следующих сценариях:

- Инициализация:
```cpp
MyClass obj1;
MyClass obj2 = obj1;
```

- Передача по значению:

```cpp
void someFunction(MyClass obj) {
    // Вызывается конструктор копирования, когда объект передаётся по значению
}
MyClass obj;
someFunction(obj);
```

- Возврат по значению:
```cpp
MyClass createObject() {
    MyClass obj;
    return obj; // Вызов конструктора копирования
}
```

- Инициализация копированием:
```cpp
MyClass obj1;
MyClass obj2(obj1);
```

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

Когда использовать переопределение операции присваивания:
- Если класс содержит хотя бы одно динамическое поле, так же как и с конструктором копирования

Когда вызывается переопределенная операция присваивания:
- Присваивание экземпляра класса другому экземпляру этого же класса

```cpp
MyClass obj1;
MyClass obj2;
obj2 = obj1;
```

- Возврат по ссылке

```cpp
MyClass& someFunction(MyClass& obj) {
    return obj;
}
MyClass obj;
someFunction(obj) = MyClass();
```

4. Как будет выполняться умножение над экземплярами классов Matrix и Vector, если операцию умножение не переопределять?

Для классов определенных пользователем, если они не являются подклассами классов с определенными операторами умножения, будет выводиться ошибка компиляции.
