Class dat
{
int day;
int month;
int year;
public:
void next(); // Элемент-функция вычисления следующего дня
dat operator++(); // Операция ++
dat operator+(int); // Операция "дата + целое" с передачей
// первого операнда через this
friend dat operator+(int,dat); // Операция с явной передачей
// всех аргументов по значению
dat(int=0,int=0,int=0);
dat(char *);
~dat();
};
//------ Функция вычисления следующего дня -----------------
// Используется ссылка на текущий объект this,
// который изменяется в процессе операции
void dat::next()
{
day++;
if (day > days[month])
{
if ((month == 2) && (day == 29) && (year%4 == 0)) return;
day=1; month++;
if (month == 13)
{
month=1; year++;
};
};
};
//------ Операция инкремента даты -------------------------
// 1. Первый операнд по указателю this
// 2. Возвращает копию входного объекта (операнда)
// до увеличения
// 3. Соответствует операции dat++ (увеличение после
// использования)
// 4. Замечание: для унарных операций типа -- или ++
// использование их до или после операнда не имеет
// значения (вызывается одна и та же функция).
dat dat::operator++()
{ // Создается временный объект
dat x = *this; // В него копируется текущий объект
next(); // Увеличивается значение текущего объекта
return(x); // Возвращается временный объект по
}; // значению
//------ Операция "дата + целое" --------------------------
// 1. Первый операнд по указателю this
// 2. Входной объект не меняется, результат возвращается
// в виде значения автоматического объекта x
dat dat::operator+(int n)
{
dat x;
x = *this; // Копирование текущего объекта в x
while (n-- !=0) x.next(); // Вызов функции next для объекта x
return(x); // Возврат объекта x по значению
};
//------ Операция "целое + дата" -------------------------
// 1. Дружественная функция с полным списком операндов
// 2. Второй операнд класса dat - передается по значению,
// поэтому может модифицироваться без изменения исходного
// объекта
dat operator+(int n, dat p)
{
while (n-- !=0) p.next(); // Вызов функции next для p
return(p); // Возврат копии объекта p
};
void main()
{
int i;
dat a, b(17,12,1990), c(12,7), d(3), e;
dat *p = new dat[10];
e = a++;
d = b+15;
for (i=0; i<10; i++) p[i] = p[i] + i;
delete [10] p;
};
Для многих переопределяемых операций тип результата совпадает с типом одного из операндов. Это позволяет выполнить подряд несколько операций в одном выражении. Возможны различные варианты реализации в соответствии со способами передачи параметров и результата: по значению или по ссылке. Отметим наиболее важные из них:
//------ Операция "дата + целое" --------------------------
// 1. Функция с неявным первым операндом по указателю this
// 2. Меняется значение текущего объекта
// 3. Результат - ссылка на текущий объект
dat& dat::operator+ (int n)
{
while (n-- !=0) next(); // Вызов next с текущим объектом
return(*this); // Возврат ссылки на объект this
};
//------ Операция "дата + целое" -------------------------
// 1. Дружественная функция с полным списком аргументов
// 2. Первый операнд класса dat - ссылка, меняется при
// выполнении операции
// 3. Результат - ссылка на операнд
dat& operator+ (dat& p,int n)
{
while (n-- !=0) p.next(); // Вызов next для объекта p,
// заданного ссылкой
return(p); // Возврат ссылки на p
};
//----- Операция "целое + дата" --------------------------
// 1. Дружественная функция с полным списком аргументов
// 2. Второй операнд класса dat - ссылка, меняется при
// выполнении операции
// 3. Результат - ссылка на операнд
//--------------------------------------------------------
dat& operator+ (int n, dat& p)
{
while (n-- !=0) p.next(); // Вызов next для объекта p,
// заданного ссылкой
return(p); // Возврат ссылки на p
};
void main()
{
dat a,b; // "Арифметические" эквиваленты
a + 2 + 3; // a = a + 2; a = a + 3;
5 + b + 4; // b = 5 + b; b = b + 4;
};
Во всех трех случаях ссылка на операнд - объект класса возвращается в качестве результата. Все действия, выполняемые операцией, реализуются в том же объекте, который "накапливает" результат.
Естественный "арифметический" вид переопределяемых операций получается, когда результат возвращается по значению не в виде ссылки, а в виде объекта:
//------ Операция "дата + целое" --------------------------
// 1. Функция с неявным первым операндом по указателю this
// 2. Изменяется автоматический объект - копия операнда
// 3. Результат - значение автоматического объекта
dat dat::operator+ (int n)
{
dat tmp = *this; // Объект - копия операнда
while (n-- !=0) tmp.next(); // Вызов next с объектом tmp
return(tmp); // Возврат значения объекта tmp
};
//------ Операция "дата + целое" -------------------------
// 1. Дружественная функция с полным списком аргументов
// 2. Первый параметр класса dat передается по значению,
// является копией первого операнда и меняется при
// выполнении операции
// 3. Результат - значение формального параметра
dat operator+ (dat p,int n)
{
while (n-- !=0) p.next(); // Вызов next для объекта p,
// копии операнда
return(p); // Возврат значения
}; // формального параметра
Во втором случае, когда формальный параметр - операнд передается по значению, он является отдельным объектом, в который копируется объект - фактический параметр. Поэтому его изменение не затрагивает входного операнда. Кроме того, в обоих случаях при возвращении объекта в качестве результата транслятор создает в вызывающей функции временный объект, в который копируется содержимое объекта-результата в операторе return. Дополнительная проблема для таких объектов заключается в их корректном конструировании.
При отсутствии переопределения операции присваивания производится побайтное копирование объектов. Такая интерпретация операции присваивания некорректна, если объект имеет указатели на динамические переменные или массивы, идентификаторы связанных ресурсов и т.д.. При копировании таких объектов необходимо сначала уничтожить связанные динамические переменные и ресурсы левого операнда, а затем заново резервировать, но уже с параметрами, необходимыми для интерпретации операции присваивания: