ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ В C++ (4-Е ИЗДАНИЕ) (часть 8) онлайн

Арифметические операции

В программе ENGLCON из главы 6 мы рассматривали два объекта класса Distance, которые складывались с помощью метода add_dist();

dist3.add_dist ( dist1, dist2 );

Используя перегрузку операции +, мы можем отказаться от этого непригляд- ного выражения и воспользоваться таким:

dist 3 = dist1 + dist2;

В листинге программы ENGLPLUS реализована эта возможность:

// engplus.cpp

// перегрузка операции + для сложения переменных типа Distances

#include <iostream>

using namespace std;

///////////////////////////////////////////////////////////

class Distance  // класс английских мер длины

{

  private:

    int feet;

    float inches;

  public:

    // конструктор без параметров

    Distance ( ) : feet ( 0 ), inches ( 0.0 )

      { }

    // конструктор с двумя параметрами

    Distance ( int ft, float in ) : feet ( ft ), inches ( in )

      { }

    // получение информации от пользователя

    void getdist ( )

      {

        cout << "\nВведите футы: "; cin >> feet;

        cout << "Введите дюймы: ";  cin >> inches;

}

    // показ информации

    void showdist ( )

      { cout << feet << "\'-" << inches << '\"'; }

    // сложение двух длин

    Distance operator+ ( Distance ) const;

};

///////////////////////////////////////////////////////////

// сложение двух длин

Distance Distance::operator+ ( Distance d2 ) const

{

  int f = feet + d2.feet;       // складываем футы

  float i = inches + d2.inches; // складываем дюймы

  if ( i >= 12.0 )              // если дюймов стало больше 12

  {

    i -= 12.0;                  // то уменьшаем дюймы на 12

    f++;                        // и увеличиваем футы на 1

  }

  return Distance ( f, i );     // создаем и возвращаем временную переменную

}

///////////////////////////////////////////////////////////

int main ( )

{

  Distance dist1, dist3, dist4;  // определяем переменные

  dist1.getdist ( );             // получаем информацию

 

  Distance dist2 ( 11, 6.25 );   // определяем переменную с конкретным значением

 

  dist3 = dist1 + dist2;         // складываем две переменные

 

  dist4 = dist1 + dist2 + dist3; // складываем несколько переменных

 

  // показываем, что же у нас получилось

  cout << "dist1 = "; dist1.showdist ( ); cout << endl;

  cout << "dist2 = "; dist2.showdist ( ); cout << endl;

  cout << "dist3 = "; dist3.showdist ( ); cout << endl;

  cout << "dist4 = "; dist4.showdist ( ); cout << endl;

 

  return 0;

}

 

Для того чтобы показать, что результат сложения может быть использован в других операциях, мы выполнили в функции main() следующие действия: сло- жили dist1, dist2 и dist3, чтобы получить dist4 (значение которой представляет собой удвоенное значение переменной dist3), в строке:

dist4 = dist1 + dist2 + dist3;

Вот результат работы программы:

Введите футы: 10 Введите дюймы: 6.5

dist1 = 10'-6.5"  -              ввод пользователя

dist2 = 11'-6.25"               -              предопределено в программе

dist3 = 22'-0.75"               -              dist1+dist2

dist4 = 44'-1.5"  -              dist1+dist2+dist3

Объявление метода operator+() в классе Distance выглядит следующим образом: Distance operator+ ( Distance );

Эта операция возвращает значение типа Distance и принимает один аргумент типа Distance. В выражении:

dist3 = dist1 + dist2;

важно понимать, к каким объектам будут относиться аргументы и возвраща- емые значения. Когда компилятор встречает это выражение, то он просматри- вает типы аргументов. Обнаружив только аргументы типа Distance, он выполняет операции выражения, используя метод класса Distance operator+(). Но какой из объектов используется в качестве аргумента этой операции — dist1 или dist2? И не нужно ли нам использовать два аргумента, так как мы складываем два объекта?

Существует правило: объект, стоящий с левой стороны операции (в нашем случае dist1), вызывает функцию оператора. Объект, стоящий справа от знака операции, должен быть передан в функцию в качестве аргумента. Операция воз- вращает значение, которое мы затем используем для своих нужд. В нашем случае мы присваиваем его объекту dist3. Рисунок 8.2 иллюстрирует все эти действия.

Рис. 8.2. Перегрузка бинарной операции с одним аргументом

В функции operator+() к левому операнду мы имеем прямой доступ, исполь- зуя feet и inches, так как это объект, вызывающий функцию. К правому операн- ду мы имеем доступ как к аргументу функции, то есть как d2.feet и d2.inches.

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

верно для функции и операторов, являющихся дружественными для класса. Мы обсудим имеющиеся возможности C++ в главе 11).

Для вычисления значения функции operator+() мы сначала складываем зна- чения feet и inches обоих операндов (корректируя результат, если это необходи- мо). Полученные значения f и i мы затем используем при инициализации безы- мянного объекта класса Distance, который затем будет возвращен в выражение.

return Distance ( f, i );

Это похоже на расположение, используемое в COUNTPP3, за исключением то- го, что конструктор принимает два аргумента вместо одного. В строке

dist3 = dist1 + dist2;

функции main() затем присваивается значение безымянного объекта класса Distance переменной dist3. Сравните это интуитивно-понятное выражение с ис- пользованием вызова функции для выполнения той же задачи, как это было сде- лано в программе ENGLCON из главы 6.

Похожие методы вы сможете создать в классе Distance для перегрузки других операций. Тогда вы сможете выполнять вычитание, умножение и деление с объ- ектами этого класса, используя обычную запись выражений.

 

10