Во многих случаях при перегрузке операторов с помощью функций-"друзей" нет никакого преимущества по сравнению с использованием функций-членов класса. Однако возможна ситуация (когда нужно, чтобы слева от бинарного оператора стоял объект встроенного типа), в которой функция-"друг" оказывается чрезвычайно полезной. Чтобы понять это, рассмотрим следующее. Как вы знаете, указатель на объект, который вызывает операторную функцию-член, передается с помощью ключевого слова this. При использовании бинарного оператора функцию вызывает объект, расположенный слева от него. И это замечательно при условии, что левый объект определяет заданную операцию. Например, предположим, что у нас есть некоторый объект ob, для которого определена операция сложения с целочисленным значением, тогда следующая запись представляет собой вполне допустимое выражение.

ob + 10; // будет работать

Поскольку объект ob стоит слева от оператора "+", он вызывает перегруженную операторную функцию, которая (предположительно) способна выполнить операцию сложения целочисленного значения с некоторым элементом объекта ob. Но эта инструкция работать не будет.

10 + ob; // не будет работать

Дело в том, что в этой инструкции объект, расположенный слева от оператора "+", представляет собой целое число, т.е. значение встроенного типа, для которого не определена ни одна операция, включающая целое число и объект классового типа.

Решение описанной проблемы состоит в перегрузке оператора "+" с использованием двух функций-"друзей" В этом случае операторной функции явным образом передаются оба аргумента, и она вызывается подобно любой другой перегруженной функции, т.е. на основе типов ее аргументов. Одна версия операторной функции operator+() будет обрабатывать аргументы объект + int-значение, а другая — аргументы int-значение + объект. Перегрузка оператора "+" (или любого другого бинарного оператора) с использованием функций-"друзей" позволяет ставить значение встроенного типа как справа, так и слева от оператора. Реализация этого решения показана в следующей программе.

#include

using namespace std;

class CL {

 public:

  int count;

  CL operator=(CL obj);

  friend CL operator+(CL ob, int i);

  friend CL operator+(int i, CL ob);

};

CL CL::operator=(CL obj)

{

 count = obj.count;

 return *this;

}

// Эта версия обрабатывает аргументы

// объект + int-значение.

CL operator+(CL ob, int i)

{

 CL temp;

 temp.count = ob.count + i;

 return temp;

}

// Эта версия обрабатывает аргументы

// int-значение + объект.

CL operator+(int i, CL ob)

{

 CL temp;

 temp.count = ob.count + i;

 return temp;

}

int main()

{

 CL o;

 o.count = 10;

 cout << o.count << " "; // выводит число 10

 o=10+o; // сложение числа с объектом

 cout << o.count << " "; // выводит число 20

 o=o+12; // сложение объекта с числом

 cout << 0.count; // выводит число 32

 return 0;

}

Как видите, операторная функция operator+() перегружается дважды, позволяя тем самым предусмотреть два возможных способа участия целого числа и объекта типа CL в операции сложения.

Использование функций-"друзей" для перегрузки унарных операторов

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

// Перегрузка префиксной формы оператора "++".

three_d three_d::operator++()

{

 х++;

 у++;

 z++;

 return *this;

}

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

Перейти на страницу:

Все книги серии Изучайте C++ с профессионалами

Похожие книги