Част 13
Аритметика за потребителски дефинираните типове
Всеки един програмен език поддържа аритметични действия с предефинираните си типове - например за основните типове данни (предефинираните типове short, int, long, float, double и long double) в C++ има операции на събиране, изваждане, умножение и делене. В лекции 11 и 12 на този курс видяхме, че можем да извършваме аритметични действия с типовете, които са дефинирани от нас. Нещо повече, C++ позволява и дефиниране на аритметичните оператори (+,-, * и /) за потребителските типове и то така, че вместо кода t3.add(t1, t2) да стои по-прегледният t3 = t1 + t2. Но за това по-късно в нашия курс - сега нека разгледаме някои тънкости при работата с потребителски дефинираните типове.
1. Достъп до частните данни (Private Data). Във функцията add(complex_number compl_num) от част 11 имаме достъп до променливите real и imaginary на променливата (обекта) compl_num, въпреки че те са декларирани с ключовата дума private. Ето дефиницията на класа complex_number.
class
complex_number
{
private:
float real; // real
part
float imaginary; // imaginery part
public:
void set()
{
char dummy; // for comma
cout << "Enter number (format Re, Im): ";
cin >> real >> dummy >> imaginary;
}
void display()
{
cout << '('
<< real // real part
<< ','
<< imaginary // imaginary part
<< ')';
}
void add(complex_number compl_num)
{
real += compl_num.real;
imaginary += compl_num.imaginary;
}
}; // class complex_number
Това е така, защото compl_num е от същия клас complex_number на обекта c1, който извиква функцията - c1.add(c2). Наистина частните променливи (и функции) на даден клас са недостъпни за "външния свят" (например в main()), но са напълно достъпни във функциите на същия клас.
Аналогично в част 12 имаме достъп във функцията add(airtime at1, airtime at2) до променливите minutes и hours на обектите at1 и at2 от класа airtime, въпреки че и двете променливи са декларирани като частни.
class
airtime
{
private:
int minutes; // 0 to 59
int hours; // 0 t0 23
public:
void set()
{
char dummy; // for colon
cout << "Enter time (format 23:59): ";
cin >> hours >> dummy >> minutes;
}
void display()
{
cout << hours << ':'
<< setfill('0')
<< setw(2) << minutes;
}
void add(airtime at1, airtime at2)
{
minutes = at1.minutes + at2.minutes; // add minutes
hours = at1.hours + at2.hours;
// add hours
if(minutes > 59)
// if carry,
{
minutes = minutes - 60;
// adjust minutes
hours = hours + 1;
// and hours
}
if(hours > 23)
// if carry,
hours = hours - 24;
// adjust hours
}
};
// class airtime
2. Превръщане на обекти едни в други. В C++ се поддържа автоматично превръщане между обектите от предефинираните типове. Т.е. ако сме дефинирали num като целочислена променлива, а quantity е променлива от тип float, то следните редове ще дадат стойност 12.0 на променливата quantity.
int
num = 12;
float
quantity;
quantity = num;
Обратното също е възможно, но целочислената променлива ще получи само цялата част (в случая 12):
float
quantity = 12.56;
int
num;
num = quantity;
Но в C++ няма механизъм за превръщане на обект от предефиниран тип в обект от потребителски дефиниран тип и обратно. (Казахме обект, защото всяка една променлива даже от предефинираните типове се разглежда от C++ като обект.) Няма такъв механизъм, защото компилаторът не знае какви точно класове ще създаде потребителят. Затова задача на потребителя е да създаде такива превръщания.
Като пример за превръщане ще разгледаме превръщане на целочислената променлива "минути" в стойност от тип airtime; примерът е взет от книгата на Лафоор [1].
//
timecnv1.cpp
//
a class that models a time data type
//
includes a member function to convert minutes to airtime
#include
<iostream.h>
#include
<iomanip.h> // for setw(), etc.
#include
<conio.h>
//for getche()
class
airtime
{
private:
int minutes; // 0 to 59
int hours; // 0 to 23
public:
void set()
{
char dummy; // for colon
cout << "Enter time (format 23:59): ";
cin >> hours >> dummy >> minutes;
}
void display()
{
cout << hours << ':'
<< setfill('0') << setw(2) << minutes;
}
// convert minutes to airtime
void MinsToAirtime(int imins)
{
hours = imins / 60;
minutes = imins - hours*60;
}
};
void
main()
{
airtime t1;
int iminutes; // minutes (can
be > 59)
char choice;
do
{
cout << "Enter minutes (for example, 241): ";
cin >> iminutes;
t1.MinsToAirtime(iminutes);
cout << "t1 = ";
t1.display(); // display t1
cout << "\nDo another (y/n)? ";
cin >> choice;
} while(choice != 'n');
// stop the flow on the monitor
getch();
} //end main
Функцията MinsToAirtime(int imins) има един аргумент imins от целочислен тип. В тялото на функцията се намира целочисленото делене на минутите със 60: hours = imins / 60;. Написахме целочислено понеже hour и imins са от целочислен тип и съответно резултатът ще е целочислен. На следващия ред се намира остатъкът от минутите, след като се извадят от всички минути минутите в намерените часове.
3. Извикване една друга на функциите на класа. Нека разширим още малко класа airtime като въведем умножение на променлива от него с целочислено число. Това би било необходимо, например, ако знаем че една обиколка в дадено автомобилно състезание се взима за определено време и искаме да изчислим колко ще траят 12 обиколки, например.
Ще искаме да създадем функция, която да умножава един обект от тип airtime с целочислено число и да присвоява резултата на обект от тип airtime. Т.е. при извикване на функцията от вида t2.mult(t1, m) обектът t1 се умножава с целочислената променлива m и резултатът се присвоява на обекта t2. С леки изменения ето я оригиналната програма, написана от Лафоор [1].
//
timemult.cpp
//
a class that models a time data type
//
includes a member function to multiply a time by a float
#include
<iostream.h>
#include
<iomanip.h> // for setw(), etc.
#include
<conio.h> //for getche()
class
airtime
{
private:
int minutes; // 0 to 59
int hours; // 0 t0 23
public:
void set()
{
char dummy; // for colon
cout << "Enter time (format 23:59): ";
cin >> hours >> dummy >> minutes;
}
void display()
{
cout << hours << ':'
<< setfill('0') << setw(2) << minutes;
}
// convert minutes to airtime
void MinsToAirtime(int imins)
{
hours = imins / 60;
minutes = imins - hours*60;
}
// multiply airtime by float
void mult(airtime at1, int mplier)
{
// convert to minutes
int im = at1.hours * 60 + at1.minutes;
im *= mplier; //
do the multiply
MinsToAirtime(im); // convert back to airtime
}
};
// class airtime
void
main()
{
airtime t1, t2;
// create airtime variables
int m;
// multiplier
char choice;
do
{
cout << "For t1, "; // get t1 from user
t1.set();
// set t1
cout << "Enter multiplier: ";
cin >> m;
// get multiplier
t2.mult(t1, m); // multiply t1 by m, result in t2
cout << "t2 = ";
t2.display();
// display t2
cout << "\nDo another (y/n)? ";
cin >> choice;
} while(choice != 'n');
// stop the flow on the monitor
getch();
} //end main
Във функцията mult първо се изчисляват минутите и се записват в локалната променлива im. В следващия ред тази променлива се умножава с числото mplier и резултатът се присвоява на нея im *= mplier. Припомнете си операторът *= ! Предното присвояване означава следното im = im*mplier. Полученият резултат е в минути, затова се извиква функцията на класа MinsToAirtime(im), която преобразува минутите в часове и минути, т.е. в обект от класа airtime.
* * *
В заключение ще споменем, че аритметиката не е за всички класове. Например за дефинирания клас HotDogStand в част 4 дефинирането на операцията събиране (или изваждане) на пръв поглед изглежда разумно, защото ще можем да съберем кремвишите и хлебчетата например на два щанда (павилиона). Но функционално погледнато (т.е. от практическа гледна точка) при управлението на няколко павилиона няма такава операция като обединяване на два щанда в един - защото има продавачи и друг инвентар, пък и преместването не е разумно. Друг по-безсмислен пример е събирането на обекти от клас Airplane, дефиниран в част 2 на този курс.
Литература
[1] Robert Lafore; C++ Interactive Course. Waite Group Press, Macmillan Computer Publishing, 1996.
Автор: Проф. Процесор Аритметиков
Keywords: С++,
OOP programming , C++ , Classes , Inheritance , Reusability , Creating
New Data Types , Polymorphism and Overloading
Ключови думи: клас
, обект, обектно ориентирано програмиране , полиморфизъм switch if else
?