Причины использования средств перегрузки операторов
Поможем в ✍️ написании учебной работы
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой

В языке Си++ имеются средства не только перегрузки функций, но и перегрузки встроенных операций. В этом случае имеется возможность обеспечить собственный алгоритм выполнения встроенной операции для данных, тип которых определен пользователем. Это предоставляет возможность использовать стандартные правила записи и интерпретации выражений для данных, тип которых отличается от стандартных типов, используемых в этих выражениях.

Например, записано если арифметическое выражение a+b/(c+b), то если a,b,c – данные арифметического типа (int, double, float), то транслятор сгенерирует соответствующую последовательность команд для реализации вычисления. При этом транслятор учтет порядок (приоритет) выполнения операций (+,/) и необходимые стандартные преобразования из одно типа в другой с целью приведения выражения к одному типу.

В случае использования средств перегрузки операций это выражение может быть записано для ситуации, когда величины a,b,c - являются объектами. Отличие заключается в том, что алгоритм выполнения операций + и / должен быть определен заранее пользователем (то есть операции + и / должны быть перегружены). Если этого не сделать, то, естественно, транслятор выдаст сообщение о том, что такой тип данных не может быть использован. Порядок же вычисления выражения по приоритетам останется прежним.

Конечно, можно было бы использовать функции для вычисления этого выражения. Однако, такая запись была бы намного более громоздкой, что приводило бы к большому количеству ошибок. Особенно, это было бы неудобно при увеличении размера выражения.

Формат операторов перегрузки

Перегрузка операции заключается в том, выполнение операции оформляется в виде функции , которая имеет специальное название:

оperator @, где @ - символ перегружаемой операции. Например, *, +,++ и т.д. Однако, существуют определенные ограничения на список перегружаемых операций.

В частности функция имеет следующий формат записи:

 тип operator@ (тип F1,тип F2) // заголовок функции

 { тело функции }

 

Например,

M1 operator+( M1 obj1, M1 obj2) //заголовок функции

{M1 x; // тело функции; локальный объект x

…………………………

…………тело функции…………………

return x;

};

……………………….

int main()

{ M1 t1,t2,t3; .// определение 3-х объектов класса М1

…………….

t3=t1+t2; // равносильно записи t3=operator+(t1,t2);

…………….

 return 0; }

В приведенном выше примере представлен частный случай перегрузки операций. На самом деле, существуют определенные правила перегрузки операций. Рассмотрим некоторые из них.

1. Перегружаемая функция может быть членом класса или дружественной функцией.

2. Если функция является членом-класса, то для бинарной операции она имеет один формальный параметр; для унарной операции функция не имеет параметров.

Первый операнд в операции транслятор рассматривает как объект, для которого вызывается перегружаемая операция.

Например, выражение t1+t2 рассматривается транслятором как t1.operator+(t2), где t1,t2 – объекты некоторого класса.

3. Если функция является дружественной, то для двуместной операции она имеет два формальных параметра; для одноместной операции функция имеет один формальный параметр.

То же самое выражение t1+t2 рассматривается как operator+(t1,t2).

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

Заданы величины X1,X2,X3 - объекты некоторого класса q1.

Членами-данных объекта являются динамические массивы.

Составить программу вычисления объекта X4=X1*X2*3;

Результат операции перемножения объектов класса q1 должен представлять суммарный массив целых чисел: в начале этого массива должен быть расположен массив левого сомножителя, а за ним должен быть расположен массив правого сомножителя.

Далее представлена программа реализации такой задачи с использованием оператора перегрузки операции умножения*.

 

Вариант 1 – оператор перегрузки является членом-функцией класса

В этом случае запись Х1*Х2 рассматривается как Х1. operator *(Х2), где Х1- объект, для которого вызывается функция operator *, Х1- левый сомножитель,Х2- объект, правый сомножитель

#include<iostream.h>

#include <conio.h>

class q1 // описание класса q1

{

int *x;       // указатель на массив целого типа

int n;        //     размер массива

public:

q1(int *y,int n1) // 1-ый конструктор

{ x=new int [n1]; // динамическое выделение памяти

  for(int i=0;i<n1;i++) // передача внешнего массива по указателю

       {

       x[i]=y[i];

       cout<<"x[i]="<<x[i]<<" y[i]="<<y[i]<<endl;

       }

       n=n1; // запоминание действительного размера массива

} // конец 1-го конструктора

 

 

q1()         /*2-ой конструктор, ничего не делает, инициализация членов данных отсутствует, необходим для создания локального объекта */

{} /* пустое тело конструктора*/

 

q1 operator*(q1 obj)     // функция перегрузки операции умножения *

{ q1 y;  //     локальный объект для результата

        y.x=new int[n+obj.n]; //запрос памяти под суммарный массив в объекте y

        for(int i=0;i<n;i++) /*перепись массива левого сомножителя в локальный объект y*/

       y.x[i]=x[i];

        for(i=0;i<obj.n;i++)          /*дополнение массива локального объекта y массивом правого сомножителя*/

       y.x[i+n]=obj.x[i];

       y.n=n+obj.n;                   /*фиксирование суммарной длины массива в локальном объекте y*/

        return y;   //     возврат значения результата, т. е. объекта y

       }// конец перегружаемой операции умножения*

 

void vivod()        //     функция вывода массива объекта

{

  for(int i=0;i<n;i++)

       {

       cout<<"x[i]="<<x[i]<<endl;

       }

}

 

}; // конец определения класса q1

 

int main()              //     главная функция

{ clrscr();

int f1[4]={4,3,2,1}; //инициализация массива f1

int f2[5]={8,8,8,8,8,};// инициализация массива f2

q1 X1(f1,3),X2(f2,2),X3(f2,5); // инициализация трех объектов

q1 X4; /*определение результирующего объекта Х1 без инициализации по 2-ому конструктору*/

X4=X1*X2*X3; //вычисление Х4 по перегруженной операции умножения*

X4.vivod();        //     вывод результата, объекта X4

return 0;

}

 

Замечание.

Оператор X4=X1*X2*X3; в действительности с точки зрения вызова функций интерпретируется транслятором как Х4=(Х1.operator*(Х2)).operator(Х3) .

Естественно, можно было бы и пользователю записать такое выражение, но такая запись очень громоздка и имеет большую вероятность ошибки. При увеличении количества сомножителей недостатки такой формы записи становятся еще более наглядными.

 

Вариант 2 – оператор перегрузки является дружественной функцией класса

В этом случае запись Х1*Х2 рассматривается как operator *(Х1,Х2), где Х1- объект, левый сомножитель, Х2- объект, правый сомножитель, а функция operator * имеет право обращаться при выполнении к закрытым элементам объектов класса q 1 , так как она является дружественной к классу q 1.

Дата: 2019-03-05, просмотров: 213.