hkjCJgcQqF
.pdf//сдвиг десятичной точки на 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