Структуры - введение в объектно-ориентированное программирование

Раньше для хранения данных использовались простые типы данных: числа, строки и т.д. Тем не менее, многие объекты, которые возникают в программировании, нельзя охарактеризовать только одной числовой или строковой величиной. Например, точка на плоскости задается парой действительных чисел (x, y), а данные о человеке можно задавать при помощи нескольких строк (фамилии, имени, отчества) и числового параметра: года рождения.

Поэтому удобным является использование объектов, объединяющих сразу ряд параметров, каждый из которых может фигурировать, как отдельная переменная.

Для этого используются специальные типы данных, которые в языке C называются структурами, а в языке C++ классами. Например, структура Point, задающая точку на плоскости и содержащая два действительных числа x и y может быть задана следующим образом:

struct Point
{
    double x;
    double y;
};

Переменные x и y, входящие в структуру Point, называются полями структуры. Определение структуры дается вне всех функций (и, обычно делается перед объявлением всех функций). Определение структуры обязательно завершается точкой с запятой.

После этого мы можем работать с Point, как с новым типом данных, содержащим два поля: x и y. Примеры создания переменной и массива переменных типа Point:

     Point P, Arr[10];

Чтобы обратиться к полю какой-либо структуры, используется оператор "точка". Его левый операнд – идентификатор переменной типа структура, правый операнд – имя поля. Например, P.x или Arr[i].y.

Например, считать координаты точки, сохранить их в переменной P и вывести на экран расстояние от начала координат до этой точки можно следующим образом:

     cin >> P.x >> P.y;
     cout << sqrt(P.x * P.x + P.y * P.y);

По сути, величины P.x и P.y являются независимыми переменными, скомбинированными в один объект. С этим объектом можно работать, как с единым целым, например, можно выполнять присваивания вроде Arr[i]=P, можно сохранить набор точек в одном массиве и т.д.

Аналогично, можно определить структуру типа Person для хранения информации о человеке:

     struct Person
     {
         string FirstName; // Имя
         string LastName;  // Фамилия
         int    BirthYear; // Год рождения
     };

Теперь можем работать с данными типа Person:

     Person Vasya;
     Vasya.FirstName = "Василий";
     Vasya.LastName = "Пупкин";
     Vasya.BirthYear = 1990;
     cout << Vasya.FirstName << " " << Vasya.LastName <<
         " родился в " << Vasya.BirthYear << " году" << endl;

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

Например, пусть мы хотим определить структуру Circle для определения окружности. Окружность задается центром и радиусом. Радиус – это действительное число (поле Radius типа double), а центр – это, конечно же, точка, то есть поле Center имеет тип Point . Получили:

     struct Circle
     {
         Point Center;
         double Radius;
     };

Дальше с такими "вложенными" структурами можно работать так:

     Circle A;
     A.Radius = 10;
     A.Center.x = -3;
     A.Center.y = 15;

Упражнения на проектирование структуры “Point”

Создайте структуру Point, определите для нее конструктор, необходимые арифметические операции, вывод на экран. У структуры Point два поля: x и y.

A: Самая дальняя точка

Программа получает на вход число N, далее координаты N точек. Выведите координаты точки, наиболее удаленной от начала координат.

Для решения этой задачи напишите метод dist, который возвращает расстояние от точки до начала координат.

Ввод Вывод
2
1 2
2 3
2 3

B: Центр масс

Выведите координаты центра масс данного множества точек (учтите, что это —два действительных числа).

Определите операции сложения точек, умножения точки на число, деления точки на число.

Ввод Вывод
2
1 2
2 3
1.5 2.5

C: Диаметр множества

Выведите диаметр данного множества – максимальное расстояние между двумя данными точками.

Для этого удобно определить операцию разности двух точек, возвращающую разность двух радиус-векторов, затем вызвать метод, вычисляющий длину данного радиус-вектора.

Ввод Вывод
3
1 1
1 0
0 0
1.4142135623731

D: Сортировка

Определите для точек оператор сравнения “<”, сравнивающую точки по значению расстояния от начала координат. Отсортируйте данные точки в порядке возрастания расстояния от начала координат используя функцию sort из файла algorithm.

Ввод Вывод
3
1 0
-1 -1
0 0
0 0
1 0
-1 -1

E: Максимальный периметр

Среди данных точек найдите три точки, образующие треугольник с наибольшим периметром. Выведите данный периметр.

Для нахождения периметра треугольника напишите отдельную функцию double Perimeter(Point A, Point B, Point C).

Ввод Вывод
4
0 0
0 1
1 0
1 1
3.41421356237309

F: Максимальная площадь

Среди данных точек найдите три точки, образующие треугольник с наибольшей площадью. Выведите данную площадь.

Для нахождения площади треугольника напишите отдельную функцию double Area(Point A, Point B, Point C).

Ввод Вывод
4
0 0
0 1
1 0
1 1
0.5

Упражнения на проектирование структуры “Fraction”

Структура Fraction должен иметь два поля: числитель a и знаменатель b. Оба поля должны быть типа int.

Для класса Fraction определите конструкторы, которые могут принимать следующие виды параметров:

У каждой дроби существует единственное каноническое представление. Каноническое представление: это такое представление \(\frac{a}{b}\), что \(b>0\), \( (a, b) = 1\). Класс должен иметь метод reduce, который приводит дробь к каноническому представлению. После каждой операции с дробями (в том числе и в конструкторе) необходимо вызывать метод reduce для сокращения дроби.

Необходимо определить вывод дроби в формате a/b в каноническом представлении, если же дробь является целым числом, то просто значение этого числа.

G: Метод reduce и вывод дроби

Необходимо реализовать следующую функциональность структуры:

  1. Метод reduce.
  2. Конструкторы Fraction(), Fraction(int), Fraction(int, int). Конструктор должен вызывать метод reduce.
  3. Вывод дроби.

Методика тестирования следующая. Проект должен содержать два файла: fraction.h, содержащий описание и реализацию структуры и fraction.cpp, подключающий fraction.h и содержающий функцию main. На проверку сдается только файл fraction.h, после чего проводится его тестирование на соответствие спецификации.

H: Считывание дроби

Реализовать считывание дроби из потока istream, перегрузив оператор считывания >>. При считывании дробь имеет один из двух форматов: либо целое число, либо два целых числа через дробную черту без пробелов, при этом только числитель может иметь знак “-”.

I: Сравнения

Определите операторы <, <=, >, >=, ==, !=. Сравнения необходимо реализовать для типов int, double, Fraction, при этом значение типа Fraction может быть как правым, так и левым операндом.

J: Сложение

Определите оператор сложения + так, чтобы можно было складывать:

K: Вычитание

Определите оператор вычитания.

L: Умножение и деление

Определите операторы умножения и деления.

M: Операторы присваивания

Определите операторы +=, -=, *=, /= для случая, когда правый операнд имеет тип Fraction или int.

Пример определения оператора:

Fraction & operator+= (Fraction &, Fraction)