Програмен език C++

Част 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.

Автор: Проф. Процесор Аритметиков

.
[ това е материал от брой 18 от април 2008 г. на списание "Коснос" www.kosnos.com ]

Keywords: С++,  OOP programming , C++ , Classes , Inheritance , Reusability , Creating New Data Types , Polymorphism and Overloading
Ключови думи: клас , обект, обектно ориентирано програмиране , полиморфизъм switch if else ?