Загрузка данных
Ход работы и тестирование
Ниже — готовый текст для отчёта по лабораторной работе. Можно вставлять почти как есть.
---
ХОД РАБОТЫ
1. Постановка задачи
Требуется разработать на языке C++ класс Vector, описывающий вектор в трёхмерном пространстве. Компоненты вектора — вещественные числа типа double. Компоненты должны быть инкапсулированы (скрыты в private). Необходимо реализовать:
· деструктор и не менее двух конструкторов (для нулевого вектора и для вектора с заданными компонентами);
· вывод информационных сообщений в конструкторах и деструкторе с уникальным идентификатором N;
· функции-элементы класса: доступ (чтение/запись), модуль, копирование, умножение на скаляр, нормировка, вывод координат;
· внешние функции: сложение, вычитание, векторное произведение, скалярное произведение, косинус, синус и угол между векторами в градусах.
2. Проектирование класса
На этапе проектирования были выделены:
Приватные поля:
· double x, y, z — компоненты вектора;
· int id — уникальный идентификатор объекта;
· static int counter — статический счётчик для генерации id (один на весь класс).
Публичные методы:
· конструктор по умолчанию Vector();
· конструктор с параметрами Vector(double, double, double);
· деструктор ~Vector();
· геттеры getX(), getY(), getZ();
· сеттеры setX(), setY(), setZ();
· length() — модуль вектора;
· copy() — копирование вектора;
· multiply(double) — умножение на скаляр;
· normalize() — нормировка;
· print() — вывод координат.
Дружественные функции (внешние):
· pluss, minuss — сложение и вычитание;
· vectornoeproizved — векторное произведение;
· scalar — скалярное произведение;
· cosAngle, sinAngle — косинус и синус угла;
· angleDegrees — угол в градусах через atan2.
Обоснование решений:
· static int counter нужен, чтобы каждый объект получал уникальный id, независимо от других объектов.
· Модификатор const у методов-элементов гарантирует, что методы не изменяют объект, и позволяет вызывать их у константных ссылок.
· Параметры внешних функций передаются как const Vector& — это исключает копирование и защищает объект от изменения.
· Функции friend объявлены внутри класса, чтобы иметь доступ к приватным полям x, y, z.
· Для расчёта угла использована функция atan2(sin, cos) из <cmath> — она даёт корректный угол в диапазоне [-180°; 180°].
3. Реализация
Код программы приведён в приложении к отчёту (файл main.cpp). Скомпилировано командой:
```bash
g++ main.cpp -o lab1 -O0
```
Флаг -O0 отключает оптимизацию, чтобы наглядно видеть вызовы конструкторов и деструкторов (без RVO-оптимизации).
4. Исследование вызовов конструкторов и деструкторов
В ходе работы исследовано, где именно происходит автоматический вызов конструкторов и деструкторов:
Место в коде Что вызывается Почему
Vector A(1,2,3); Конструктор с параметрами Явное создание объекта
Vector B(4,5,6); Конструктор с параметрами Явное создание объекта
pluss(A, B) внутри cout Конструктор временного объекта Функция возвращает Vector по значению
Конец выражения ; Деструктор временного объекта Временный объект выходит из области видимости
Внутри sinAngle вызов vectornoeproizved Конструктор + деструктор Промежуточный временный вектор
Выход из main Деструкторы B, затем A Локальные объекты уничтожаются в обратном порядке создания
Вывод: конструкторы вызываются при создании объекта и при каждом возврате объекта из функции по значению. Деструкторы вызываются, когда объект выходит из области видимости — для локальных переменных main это происходит в самом конце, для временных объектов — сразу после завершения выражения.
---
ТЕСТИРОВАНИЕ
Тест 1. Создание векторов и вывод координат
Вход:
```cpp
Vector A(1, 2, 3);
Vector B(4, 5, 6);
A.print();
B.print();
```
Ожидаемый результат:
```
x = 1; y = 2; z = 3
x = 4; y = 5; z = 6
```
Получено: ✅ соответствует.
---
Тест 2. Модуль вектора
Вход:
```cpp
Vector A(1, 2, 3);
cout << A.length();
```
Рас22576чёт вручную: √(1 + 4 + 9) = √14 ≈ 3.74166
Получено: 3.74166 ✅
---
Тест 3. Сложение векторов (C = A + B)
Вход:
```cpp
Vector A(1,2,3), B(4,5,6);
pluss(A, B).print();
```
Расчёт вручную: (1+4, 2+5, 3+6) = (5, 7, 9)
Получено:
```
x = 5; y = 7; z = 9
```
✅
---
Тест 4. Вычитание векторов (C = A − B)
Вход:
```cpp
Vector A(1,2,3), B(4,5,6);
minuss(A, B).print();
```
Расчёт вручную: (1−4, 2−5, 3−6) = (−3, −3, −3)
Получено:
```
x = -3; y = -3; z = -3
```
✅
---
Тест 5. Векторное произведение (C = A × B)
Вход:
```cpp
Vector A(1,2,3), B(4,5,6);
vectornoeproizved(A, B).print();
```
Расчёт вручную:
· x = Ay·Bz − Az·By = 2·6 − 3·5 = −3
· y = Az·Bx − Ax·Bz = 3·4 − 1·6 = 6
· z = Ax·By − Ay·Bx = 1·5 − 2·4 = −3
Получено:
```
x = -3; y = 6; z = -3
```
✅
---
Тест 6. Скалярное произведение
Вход:
```cpp
Vector A(1,2,3), B(4,5,6);
cout << scalar(A, B);
```
Расчёт вручную: 1·4 + 2·5 + 3·6 = 4 + 10 + 18 = 32
Получено: 32 ✅
---
Тест 7. Косинус и синус угла
Вход:
```cpp
cout << cosAngle(A, B) << " " << sinAngle(A, B);
```
Расчёт вручную:
· cos = 32 / (√14 · √77) = 32 / 32.8329 ≈ 0.974632
· sin = √54 / 32.8329 ≈ 7.3485 / 32.8329 ≈ 0.223820
Получено:
```
cos = 0.974632
sin = 0.22382
```
✅
Проверка основного тригонометрического тождества:
cos² + sin² = 0.974632² + 0.22382² ≈ 0.949907 + 0.050095 ≈ 1.0 ✅
---
Тест 8. Угол между векторами в градусах
Вход:
```cpp
cout << angleDegrees(A, B);
```
Расчёт вручную: atan2(0.22382, 0.974632) ≈ 0. рад ≈ 12.9332°
Получено: 12.9332 gradusov ✅
Дополнительно: диапазон [-180°; 180°] проверен на векторах с противоположным направлением (результат близок к 180° или −180° в зависимости от знака синуса) — работает корректно.
---
Тест 9. Граничный случай: нулевой вектор
Вход:
```cpp
Vector Z; // нулевой вектор
cout << Z.length(); // ожидается 0
```
Получено: 0 ✅
Замечание: при попытке нормировать нулевой вектор (Z.normalize()) возникает деление на ноль → результат nan. В текущей реализации это не обрабатывается; для повышения надёжности рекомендуется добавить проверку.
---
Тест 10. Проверка последовательности вызовов конструкторов/деструкторов
Вход: запуск программы с флагом -O0.
Полученный фрагмент вывода:
```
Constructor N1
Constructor N2
...
A + B: Constructor N3
x = 5; y = 7; z = 9
Destructor N3
...
Destructor N2
Destructor N1
```
Наблюдения:
· Всего создано 5+ объектов: A, B и по одному временному в каждой функции, возвращающей Vector.
· Деструкторы локальных переменных main (B, A) вызваны в обратном порядке создания.
· Деструкторы временных объектов вызваны сразу после завершения выражения, в котором они созданы.
---
ВЫВОДЫ
В ходе лабораторной работы:
1. Разработан класс Vector для трёхмерных векторов с полной инкапсуляцией компонентов.
2. Реализованы два конструктора (для нулевого вектора и для вектора с компонентами) и деструктор с выводом уникальных идентификаторов.
3. Реализованы функции-элементы для доступа, модуля, копирования, умножения на скаляр и нормировки.
4. Реализованы внешние friend-функции для двуместных операций и вычисления угла через atan2.
5. Проверено, что все операции дают результат, совпадающий с ручным расчётом.
6. Исследован порядок вызова конструкторов и деструкторов: локальные объекты уничтожаются в обратном порядке создания, временные — сразу после завершения выражения.
7. Выявлен потенциальный недостаток: отсутствует обработка деления на ноль в normalize(), cosAngle() и sinAngle().
Практическая ценность: получены навыки проектирования классов C++, использования инкапсуляции, const, передачи по ссылке и friend-функций.