Программирование калькулятора дробей

При разработке программы калькулятора дробей целесообразно сосредоточить описание дробных структур данных и операции их обработки в отдельном классе Fraction. Класс Fraction должен содержать частные (private) компоненты данные и общедоступные (public) компонентные методы обработки приватных данных. Это позволит оперировать данными класса Fraction только в компонентных методах и исключит возможность непосредственного обращения к ним из любой внешней функции программы. Исходя из этого декларация логической структуры класса Fraction должна иметь следующий формат:

class Fraction {

private: /* спецификация компонентных данных */

public: /* объявление прототипов компонентных методов */

};

В приватную часть класса Fraction следует включить спецификацию целочисленных компонентных данных, которые обозначают числитель и знаменатель дроби, как показано в следующем фрагменте класса Fraction:

class Fraction {

private:

int nominator; /* числитель */

int denominator; /* знаменатель */

public:

//некоторый код

};

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

Желаемую арифметическую обработку дробных чисел удобно реализовать с помощью компонентных оператор-функций, которые обеспечат перегрузку арифметических операций (+,-,*,/) в выражениях с объектами класса Fraction. Наличие оператор-функций позволит конструировать арифметические выражения для объектов класса Fraction в наглядной форме как для объектов простых типов. При наличии соответствующих оператор-функций будет правильно вычисляться, например, следующее выражение программы:

r=f1@f2;

где r,f1 и f2 объекты класса Fraction, а @ - знак операции.

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

Fraction operator@(Fraction&);

который отличается только символом перегружаемой операции @ (+,-,*,/). Используя эти декларации, компилятор языка C++ будет рассматривать приведенное выше выражение как следующий вызов соответствующей компонентной оператор-функции:

r=f1 operator@(f2);

Как видно из приведённой спецификации вызова, аргумент компонентной оператор-функции используется для передачи по ссылке 2-го операнда операции. Первый операнд операции неявно передается через скрытый аргумент, присущий любой компонентной функции и доступный по указателю this. Результат вычислений в теле оператор-функции возвращается в основную программу для присвоения объекту класса Fraction. Следует отметить, что передача аргумента по ссылке в данном случае выбрана из экономических соображений. Для оператор-функции допустима передача аргумента по значению. Однако, в этом случае происходит создание промежуточной копии объекта передачи в стеке оператор-функции.

Кроме компонентных оператор-функций в состав компонентных методов класса Fraction целесообразно включить 3 обычные компонентные функции:

int euclid(int,int);

int sign(int);

void ptint(void);

декларировав их в общедоступной части класса Fraction, указанным образом.

Компонентный метод euclid должен вычислять наибольший общий делитель своих аргументов, используя алгоритм Евклида. Вычисленное значение должно передаваться через код возврат метода. Этот метод предназначается для реализации алгоритмов арифметических операций с дробями в компонентных оператор-функциях класса Fraction.

Компонентный метод sign используется для определения знаков своего аргумента, возвращая (-1), если значение аргумента меньше 0 или +1, если аргумент имеет неотрицательное значение. Этот метод следует использовать для реализации алгоритма деления дробных чисел в соответствующей компонентной оператор-функции класса Fraction.

Компонентный метод print должен отображать в потоке стандартного вывода числитель и знаменатель объекта класса Fraction, от имени которого он вызван. Этот метод следует применять в программе калькулятора дробей для отображения результата операций с дробями.

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

Fraction(char*);

Через аргумент в этот конструктор должно передаваться представление дроби в виде строки символов, где числитель и знаменатель выражаются выборами цифр, которые разделяет символ '/'. Конструктор должен преобразовывать символьное представление числителя и знаменателя в целочисленные значения компонент-данных класса Fraction, используя библиотечную функцию atoi системы программирования C++.

Рассмотренные общедоступные компоненты класса Fraction можно использовать в основной функции main(int argc,char** argv) программы калькулятора дробей fc. Вычисляемое арифметическое выражение должно передаваться в функцию main через параметры командной строки вызова программы fc, так что 1-й (argv[1]) и 3-й

(argv[3]) параметры соответствуют дробным операндам.

В теле функции main следует задать 3 объекта класса Fraction для хранения операндов и результата операции. Объекты- операнды должны быть инициализированы строками соответствующих параметров командной стоки. Объект результата можно инициализировать произвольной дробью, представленной в символическом формате, например, "0/1".

Знак операции, передаваемый в функцию main через 2-й параметр командной строки, удобно рассматривать в операторе switch системы программирования C++ для выбора одного из 4-х вариантов вычисляемых дробных выражений. После вычисления выбранного выражения с помощью соответствующей компонентной оператор- функции класса Fraction ответ нужно сохранить в зарезервированном объекте-результате. Вызов компонентной функции print класса Fraction от имени объекта результата, позволит отобразить полученную дробь в потоке стандартного вывода.

Контрольные задания

1. Расширить класс Fraction перегрузкой операции присваивания (=), в которой должно быть реализовано копирование числителя и знаменателя, а также приведение результирующей дроби к несократимому виду, если это необходимо.

2. Расширить класс Fraction перегрузкой операции проверки равенства 2-х дробей (==).

3. Модифицировать класс Fraction, так чтобы перегрузку операций над его объектами обеспечивали дружественные оператор-функции. При этом необходимо учесть, что прототипы дружественных функций должны быть объявлены в декларации класса с модификатором friend и в них по ссылке должны передаваться оба операнда, т.к. скрытый указатель this на объект класса в них недоступен.

4. Усовершенствовать представление результата операций с дробями, так чтобы в случае, когда числитель больше знаменателя, выделялась целая часть числа.

5. Разработать средства контроля достоверности результатов операций с дробными числами. Например, сложение дробей должно проверяться вычитанием, а умножение - делением.

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

7. Реализовать операции сложения и вычитания с помощью приведения дробей к общему знаменателю. Для вычисления наименьшего общего кратного (Hok) знаменателей дробей, которое необходимо в этом случае, рекомендуется использовать следующее соотношение:

U'*V'=Hog(U',V')*Hok(U',V').

 

Рекомендуемая литература

1. Д. Кнут. Искусство программирования для ЭВМ, т.2 Получисленные алгоритмы - М., Мир, 1977 г.

2. П. Лукас. С++ под рукой - Киев, НИПФ "ДиаСофт", 1993 г.


 



Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: