Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

hkjCJgcQqF

.pdf
Скачиваний:
2
Добавлен:
15.04.2023
Размер:
810.94 Кб
Скачать

//сдвиг десятичной точки на 8 позиций вправо val1 = 100000000L*x;

//сдвиг десятичной точки на 7 позиций вправо val2 = 10000000L*x;

//val1-val2 = 90,000,000 * x

num = long(val1-val2); den = 90000000L;

//после создания рационального числа, преобразуем его в редуцированную форму

Reduce();

}

//проверка деноминатора на равенство 0 ( denominator is 0) if (r.den == 0)

{

cerr << "Нулевой деноминатор (A Zero denominator is invalid) \n"; exit(1);

}

// приведение объекта r к стандартной форме r.Standardize();

return istr;

}

istream& operator >> (istream& istr, Rational& r)

{

char c;

//для чтения разделителя '/' (reads the separator '/') //как друг оператор ">>" имеет доступ

//к номинатору и деноминатору объекта r

istr >> r.num >> c >> r.den;

// перегруженный оператор вывода потока. форма: P/Q ostream& operator << (ostream& ostr, const Rational& r)

{

как друг оператор ">>" имеет доступ к numerator/denominator объекта r

ostr << r.num << '/' << r.den; return ostr; }

Перегруженный оператор сложения

Rational Rational::operator+ (Rational r) const { return Rational(num*r.den + den*r.num, den*r.den);

}

// Rational subtraction (вычитание)

Rational Rational::operator- (Rational r) const { return Rational(num*r.den - r.num*den, den*r.den);

}

93

// Rational multiplication (умножение)

 

Rational Rational::operator* (Rational r) const

{

return Rational(num*r.num, den*r.den);

 

}

 

// Rational division (деление)

 

Rational Rational::operator/ (Rational r) const

{

Rational temp = Rational(num*r.den, den*r.num);

// привести в нормализованную форму (denominator –положительный) temp.Standardize();

return temp; }

// Rational отрицание

Rational Rational::operator- ( ) const { return Rational(-num, den);

}

// relational “меньше чем” ("less than")

int Rational::operator< (Rational r) const { return num*r.den < r.num*den;

}

//relational “меньше чем или равно” ("less than or equal to") int Rational::operator<= (Rational r) const

{

return num*r.den <= r.num*den;

}

//relational “равно” ("equal")

int Rational::operator== (Rational r) const

{

return num*r.den == den*r.num;

}

// relational “не равно” ("not equal")

int Rational::operator!= (Rational r) const { return num*r.den != r.num*den;

}

// relational “больше чем” ("greater than") int Rational::operator> (Rational r) const {

return num*r.den > r.num*den;

}

//relational “больше чем или равно” ("greater than or equal to") int Rational::operator>= (Rational r) const {

return num*r.den >= r.num*den;

}

//преобразовать Rational в double

Rational::operator double( ) const { return double(num)/den;

94

}

//возвратить номинатор Rational object long Rational::GetNumerator( ) const {

return num;

}

//возвратить деноминатор Rational object long Rational::GetDenominator( ) const {

return den;

}

//возвратить редуцированную форму Rational object void Rational::Reduce( ) {

long bigdivisor, tempnumerator; // tempnumerator-модуль от num

tempnumerator = (num < 0) ? -num : num; if (num == 0)

den = 1; // приведение к 0/1 else

{

//найти GCD положительных чисел:

//tempnumerator, denominator bigdivisor = gcd(tempnumerator, den);

if (bigdivisor > 1)

{

num /= bigdivisor; den /= bigdivisor;

}

}

}

#endif // RATIONAL_CLASS Описание.

Закрытый метод Standardize преобразует рациональное число в “нормальную форму” с положительным деноминатором. Конструкторы используют Standardize для преобразования числа в нормальную форму. Также используется этот метод при чтении числа или при делении двух чисел, поскольку эти операции могут привести к результату с отрицательным деноминатором. Сложение и вычитание не вызывает Standardize, потому что два знаменателя операндов уже являются неотрицательными. Закрытый метод gcd( ) возвращает наибольший общий делитель двух целых m и n :

long Rational::gcd(long m, long n) const { long remainder = m % n;

while (remainder > 0)

{

95

m = n;

n = remainder; remainder = m % n;

}

return n; }

Открытая функция Reduce() преобразует объект рациональное число в его редуцированную форму вызовом gcd().

Два конструктора этого класса действуют как операции преобразования целого (long int ) и действительного (double ) числа в рациональное (Rational ) число.

Методы GetNumerator ( ) и GetDenominator ( ) используются для доступа к данным-членам рационального числа.

Операторные функции класса Rational

Класс Rational объявляет арифметические операторы и операторы отношения как перегруженные функции-члены. Каждый бинарный оператор имеет параметр, который является правым операндом. Предположим, u, v и w - это объекты типа Rational в выражении:

w = u + v

Перегруженный оператор + является членом объекта u (левый операнд) и принимает v в качестве параметра. Возвращаемым значением является объект типа Rational, который присваивается w. Технически w = u + v оценивается как w = u. + (v)

Для выражения v = - u . С++ выполняет оператор “-” для объекта u (единственный операнд). Возвращаемым значением является объект Rational, который присваивается v. Технически v = -u оценивается как v = u. – ( )

Реализация операторных функций приведена выше.

Операторы потока класса Rational как дружественные функции

Файл <iostream > содержит объявления для двух классов с именами ostream и istream , которые обеспечивают потоковый вывод и ввод соответственно. Потоковая система ввода/вывода предоставляет

определения для потоковых

операторов ввода/вывода “>>” и “<<” в

случае базовых типов char, int,

short, long, float, double. Например:

istream&

operator>>(short v);

ostream &

operator<<(double v);

Потоковые операторы можно перегружать для реализации ввода/вывода определяемого пользователем типа. Но если перегружать операторы как функции-члены, их было бы необходимо объявлять явно в <iostream >. Это явно неудобно, поэтому используем дружественную перегрузку, которая определяет оператор вне класса, но позволяет ему иметь доступ к закрытым данным членам в классе. Параметр istr представляет поток ввода, такой как cin, и ostr представляет поток вывода, такой как cout. Так как процесс ввода/вывода изменяет состояние потока , параметр должен

96

передаваться по ссылке перегрузка оператора ввода потока, ввод в форме P/Q:

istream& operator >> (istream& istr, Rational& r)

{

char c; // для чтения разделителя '/' (reads the separator '/')

как друг оператор ">>" имеет доступ к номинатору и деноминатору объекта r

istr >> r.num >> c >> r.den;

Преобразование рациональных чисел

Конструктор класса может использоваться для построения объекта. Конструктор принимает параметры ввода и преобразует их в объект. Класс Rational имеет два конструктора, которые служат в качестве операторов преобразования типа. Первый конструктор преобразует целое в рациональное число, а второй преобразует число с плавающей точкой в рациональное число. При вызове конструктора с единственным целым параметром num он преобразует целое в эквивалентное рациональное num / 1.

Rational(int num=0, int denom=1);

Второй конструктор преобразует действительное число в рациональное . Для преобразования необходим алгоритм, который аппроксимирует произвольное число с плавающей точкой в эквивалентное рациональное. Алгоритм включает сдвиг десятичной точки в числе с плавающей точкой. В зависимости от количества значащих цифр в действительном числе результат может быть только приближенным. После создания рационального числа вызывается функция Reduce ( ), сохраняющая рациональное число в более читабельной редуцированной форме.

Rational::Rational(double x)

{

double val1, val2; val1 = 100000000L*x; val2 = 10000000L*x;

// val1-val2 = 90,000,000 * x; by truncating num = long(val1-val2);

den = 90000000L; Reduce(); }

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

Rational::operator double( ) const { return double(num)/den; }

Использование рациональных чисел

Эта программа представляет основные возможности класса Rational:

97

#include <iostream> using namespace std;

#include "rational.h" // включить заголовочный файл рациональных чисел // каждая операция сопровождается выводом

void main( ) { Rational r1(5), r2, r3; float f;

cout << "1. Rational-значение 5 (value for integer 5 is) " << r1 << endl; cout << "2.Введите рациональное число (Enter a rational number): "; cin >> r1;

f = float(r1);

cout << " Эквивалент с плавающей запятой (Floating point equivalent is) " << f << endl;

cout << "3. Введите два рациональных числа (Enter two rational numbers): "; cin >> r1 >> r2;

cout << " Результаты (Results): " << (r1+r2) << " (+) "

<<(r1-r2) << " (-) " << (r1*r2) << " (*) "

<<(r1/r2) << " (/) " << endl;

if (r1 < r2)

cout << " Отношение (меньше чем) Relation (less than): " << r1 << " < " << r2 << endl;

else if (r1 == r2)

cout << " Отношение (равно) Relation (equal to): " << r1 << " == " << r2 << endl;

else

cout << " Отношение (больше чем) Relation (greater than): " << r1 << " > " << r2 << endl;

cout << "4.Введите число с плав. запятой (Input a floating point number): "; cin >> f;

r1 = f;

cout << " Преобразование к Rational (Convert to Rational) " << r1 << endl; f = r1;

cout << " Преобразование к float (Reconvert to float) " << f << endl; char m=’0’;

while (m!=’1’) cin>>m;

}

Задание

1

1.Используя класс Rational, создайте приложение , в котором объявите действительное число pi=3.14159265 и приближение рационального числа Rational(22,7). Напишите программу, которая выполняет два следующих вычисления и печатает результаты:

98

вычислите разность между двумя числами как рациональными. Rational(pi)-Rational(22, 7);

вычислите разность между числами как действительными числами: pi-и float(Rational(22,7)

2. Используя две функции для рациональных чисел, выполните некоторые вычисления:

PrintMixedNumeric (Rational X) –//печатать число как смешанное;

SolveEquation (Ratinal, Rational, Rational ) -// решить общее уравнение //(a/b)*X + (c/d) = (e/f)

№ 2

1.Реализуйте класс Complex . Комплексное число имеет форму

x+iy, где i2 = -1. Они имеют арифметику, управляемую рядом правил:

Пусть u=a+ib, v=c+id Величина (u)=sqrt(a2+ b2)

Комплексное число, соответствующее действительному числу f, равно f+i0

Вещественная часть u равна a Мнимая часть u равна b u+v=(a+c)+i(b+d) u-v=(a-c)+i(b-d)

u*v=(ac-bd)+i(ad+bc) u/v=(ac+bd)/(c2+d2)+ i*((bc-ad)/(c2+d2)) -u=-a+i(-b)

Объявление класса Complex является следующим: class Complex

{

private: double real;

double imag; public:

Complex (double x=0.0, double y=0.0); //бинарные операторы

Complex operator+ (Complex x) const; Complex operator- (Complex x) const; Complex operator* (Complex x) const; Complex operator/ (Complex x) const; //отрицание

Complex operator- (void) const; //оператор потокового ввода/вывода //вывод в формате (real, imag)

friend ostream& operator<<(ostream& ostr, const Complex& x); };

99

2. Добавьте методы GetReal и GetImag, возвращающие вещественную и мнимую части комплексного числа. Используйте эти методы для написания функции Distance, которая вычисляет расстояние между двумя комплексными числами

double Distance (const Complex& a, const Complex& b);

3

1.Класс ModClass имеет единственный целый данное-член dataval в диапазоне 0...6. Конструктор принимает любое положительное целое v и присваивает данному-члену dataval остаток от деления на 7. dataval=v%7;

Оператор сложения складывает два объекта, суммируя их данные-члены и находя остаток после деления на 7. Например:

ModClass a(10); //dataval в равен 3; ModClass b(6) ; //dataval в b равен 6 class ModClass

{

private: int dataval;

public: ModClass(int v=0);

ModClass operator+(const ModClass &x); int GetValue( ) const;

}; Реализуйте методы этого класса.

2.Объявите и реализуйте оператор “*” как друга ModClass. Оператор умножает поля значений в двух объектах ModClass и находит остаток после деления на 7.

3.Напишите функцию ModClass Inverse( const ModClass & x); которая принимает объект x с ненулевым значением и возвращает значение y, так чтобы x*y=1 (y называется обратным значением x). (Совет : неоднократно умножайте --x на объекты со значением от 1 до 6. Один из этих объектов является обратным).

4.Перегрузите потоковый вывод для ModClass и добавьте этот метод к классу.

5.Замените GetValue, перегрузив оператор преобразования int(). Этот оператор преобразует объект ModClass в целое, возвращая dataval. operator int( );

6.Напишите функцию

void Solve(ModClass a, MadClass& x, ModClass b);

которая решает уравнение ax=b для x , вызывая метод Inverse.

4

1.Добавьте преобразователь в класс Rational, который возвращает объект ModClass.

100

2.Добавьте преобразователь в класс ModClass, который возвращает объект Rational.

3.Создайте класс Employee, который содержит имя (объект класса string)

иномер (типа long) служащего. Включите в него метод getdata(), предназначенный для получения данных от пользователя и помещения их в объект, и метод putdata(), для вывода данных. Предполагается, что имя может иметь внутренние пробелы. Напишите функцию ( main()),

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

4. Создайте класс bMoney. Он должен хранить денежные значения как double и название валюты.. Cоздайте методы, преобразующие денежную строку, введенную пользователем в double и наоборот. Напишите перегруженный метод для сложения двух объектов типа bMoney, метов конвертирования из одной валюты в другую. Напишите функцию, тестирующую класс bMoney.

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

1.Объясните различие между перегрузкой оператора с использованием функции-члена и дружественной функции.

2.Объясните, как реализуется преобразование из действительной формы в рациональную в классе Rational?

3.Объясните почему перегруженные операторы ввода и вывода, определенные для класса Rational, объявлены как глобальные функции

4.Приведите возможные последовательности определенных пользователем преобразований для следующих инициализаций.

Каким будет результат каждой инициализации class LongDouble {

operator double ( ); operator float ( ); };

extern LongDouble ldObj; int ex1 = ldObj;

float ex2 = ldObj;

Задание для самостоятельной работы

1. Создайте программу поиска подстроки в строке текста. Считайте целое n, представляющее количество строк текста в документе. Динамически выделите место для n указателей на объекты MyString. Читайте n объектов MyString. используя ReadString. Строки текста могут содержать специальные символы "X" и"Y" , например:

Уважаемый X,

101

Ваш приз находится в Y. Если Вы посетите X и укажите Ваше имя, служащий вручит Вам Ваш приз. Спасибо X за Ваш интерес к нашему конкурсу.

С уважением редакция ТВ новости Председатель комиссии

Введите строку строку poundstr, которая заменяет все вхождения "X" в документе. Введите строку ampsting, которая заменяет все вхождения "Y". Пройдите по массиву строковых указателей и выполните подстановки. Печатайте окончательный документ.

102

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]