Бьерн Страуструп - Абстракция данных в языке С++ - Перегрузка знаков операций и преобразование типов

ОГЛАВЛЕНИЕ

 

Перегрузка знаков операций и преобразование типов

    Некоторые языки предоставляют тип данных complex
  так, что для комплексных чисел программисты могут пользоваться
  непосредственно математической нотацией. Так как в С этого типа
  нет, то будет явной проверкой возможностей абстракции в том,
  насколько он может поддерживать традиционную нотацию для
  комплексных чисел (Заметим однако, что complex -
  необычный тип данных в том смысле, что при чрезвычайно простом
  представлении он имеет весьма строгие традиции по своему
  использованию.) Это таким образом в основном проверка мощности
  возможностей абстракции языка по имитации общепринятой нотации.
    В большинстве случаев внимание проектировщика привлечено
  непосредственно к нахождению хорошей реализации абстракции и
  подходящего наглядного представления ее пользователями. Цель
  проверки состоит в том, возможно ли написать код типа:

      complex x; 
      complex a = complex (1, 1.23);
      complex b = 1;
      complex c = pi;
      if (x -= a) x = a + log (b * c) / 2;

    Таким образом для комплексных чисел и для сочетания
  комплексной и скалярной констант и переменных должны быть
  определены стандартные арифметические операции сравнения.

    Ниже приводится описание очень простого класса c o m p l e x :

      class complex 
      { double re, im;
            friend complex operator+(complex, complex);
            friend complex operator*(complex, complex);
            friend int operator != (complex,complex);
      public:
            complex() { re = im = 0;}
            complex(double r) { re = r; im = 0; }
            complex(double r, double i) { re = r; im = i; }
      };

    Знак операции опознается как имя функции, если ему
  предшествует ключевое слово complex. Если операция
  используется для типа, определенного как класс, компилятор
  сгенерирует обращение подходящей функции, если таковая
  определена. Например, для комплексных переменных x, y
  сложение x + y будет интерретироваться как operator+(x,y)
  согласно вышеприведенному описанию класса complex.
  Функция сложения комплексных чисел могла бы быть определена так:

      complex  operator+(complex a1, complex a2) 
      {
          return complex(a1.re + a2.re, a1.im + a2.im);
      }

    Естественно, все имена вида c o m p l e x
  перегружены. Для гарантии того, что язык является только
  расширяемым, не изменчивым, функции-операции должны иметь хотя
  бы одним аргументом объект какого-либо класса. Объявляя функцию-
  операцию, программист может приписать стандартному знаку операции
  языка С значение, связывающего его с объектами определенного
  пользователем типа. Эти знаки операций сохраняют свое место
  в синтаксисе С, добавить новые знаки операций невозможно. Таким
  образом, невозможно изменить приоритет операций или ввести новый
  знак операции (например, **к для возведения в степень). Это
  ограничение сохраняет простоту анализа выражений языка С.

    Описание функций для унарных и бинарных операций различаются
  по числу их аргументов. Например:

      class complex { 
            . . .
            friend complex operator - (complex);
            friend complex operator - (complex, complex);
      };

    Проектировщику класса c o m p l e x для поддержки
  смешанной арифметики типа x x + 1, где x x - комплексная
  переменная, открыты три пути. Можно просто считать такие
  выражения незаконными, так что пользователь будет вынужден явно
  записывать преобразование из ???
  Другим решением может быть спецификация нескольких комплексных функций
  сложения:

      complex  operator+(complex,complex); 
      complex operator+(complex,double);
      complex operator+(double,complex);

  так, что компилятор для каждого случая выберет подходящую функцию.
  Наконец, если класс включает конструкторы, принимающие
  единственный аргумент, они могут быть использованы для
  определения преобразования типов из типа своего аргумента тип
  своего значения. Так, с учетом вышеприведенного описания класса
  c o m p l e x будет автоматически интерпретироваться
  как o p e r a t o r + (x x, c o m p l e x ( 1 )).
      Последняя возможность нарушает идею многих людей строгой
  типизации. Однако, использование второго решения практически
  утратит число необходимых функций, первое предоставляет мало
  удобств в смысле упрощения нотации для пользователя класса
  c o m p l e x . Заметим, что комплексные числа представляют
  весьма типичный пример желательности смешанной арифметики. Такие
  характерные типы данных не существуют в вакууме. Более того, для
  многих типов существует тривиальное преобразование из числовых
  и/или строковых констант С в подмножество значений данного типа
  (подобно преобразованию числовых констант С в комплексные
  значения на вещественной оси).
    Подход с использованием дружественных функций был выбран для
  того, чтобы использовать составляющие функции в функциях - операциях.
  Присущая данному представлению объектов ассиметрия не соответствует
  традиционному математическому взгляду на комплексные числа.