PDA

Просмотр полной версии : [Урок] [Цикл уроков программиста] 15. Перегрузка операции



Tracker1
30.07.2013, 20:37
Сегодня мы познакомимся с замечательной возможностью нашего любомого языка C++ - перегрузкой операций. Но сначала разберёмся, для чего это нужно.

С базовыми типами вы можете использовать любые операции: +, -, *, ++, = и многие другие. Например:


int a=2,b=3,c;
c = a + b;


Здесь над переменными типа int сначала выполняется операция +, а затем результат присваивается переменной c с помощью операции =. Над классами такое проделать не получится. Создадим простой класс:


class Counter
{
public:
int count;
Counter() : count(0) {}
};

Counter a,b,c;
a.count = 2;
b.count = 3;
c = a + b;


Здесь компилятор выдаст ошибку на последней строке: он не знает как именно нужно действовать при использовании операций = и + над объектами класса Counter. Можно решить данную проблему вот так:


class Counter
{
public:
int count;
Counter() : count(0) {}
void AddCounters (Counter& a, Counter& b)
{
counter = a.count + b.count;
}
};

Counter a,b,c;
a.counter = 2;
b.counter = 3;
c.AddCounters(a,b);


Согласитесь, использование операции + и = в данном случае сделало бы программу более понятной. Так вот, чтобы использовать стандартные операции C++ с классами, эти операции нужно перегрузить (overload).
Перегрузка унарных операций

Начнём с простых операций - унарных. Прежде всего нас интересует инкремент. При использовании данной операции над базовыми типами, к переменной можно прибавить или отнять единицу:


int a=1;
++a; // a = 2;
--a; // a = 1;


Теперь научим класс Counter использовать преинкремент (предекремент):


class Counter
{
private:
count;

public:
Counter() : count(0) {}
void operator++ ()
{
count += 1; // Можно также count++ или ++count -
// это не имеет значения в данном случае.
}
};

Counter a;
++a;
++a;
++a;


Этот код работает. При использовании операции ++ (важно чтобы этот знак находился до идентификатора!) над объектом класса Counter, происходит увеличение переменной counter объекта a.

В данном примере мы перегрузили операцию ++. Делается это созданием метода внутри класса. Единственной важной особенностью данного метода - имя идентификатора. Имя идентификатора для перегруженных операций состоит из ключевого слова operator и названия операции. Во всём остальном этот метод определяется как и любые другие.

Использовать перегруженные операции с пользовательскими типами очень просто - так же как и с обычными типами данных.
Перегрузка постфиксных операций

Примеры постфиксной операции:


int a = 3;
a++;
a--;


То есть, здесь знак операции ставится после имени идентификатора. Для использования постфиксных операций с пользовательскими типами данных нужно совсем немного:


public:
void operator++ ()
{
counter += 1;
}
void operator++ (int)
{
counter += 1;
}


Единственным отличием префиксной операции от постфиксной - ключевое слово int в списке аргументов. Но int - это не аргумент! Это слово говорит, что перегружается постфиксная операция. Теперь операцию ++ можно использовать как перед идентификатором объекта, так и после:


Counter a;
++a;
++a;
a++;
a++;

Перегрузка бинарных операций

Перегрузка операций с двумя аргументами очень похожа на перегрузку бинарных операций:


Counter operator+ (Counter t)
{
Counter summ;
summ.counter = counter + t.counter;
return summ;
}

Counter c1,c2,c3;
c1.counter = 3;
c2.counter = 2;

c3 = c1 + c2;


Какая переменная вызовет функцию operator+? В перегруженных бинарных операциях всегда вызывается метод левого операнда. В данном случае метод operator+ вызывает объект c1.

В метод мы передаём аргумент. Аргументом всегда является правый операнд.

Кроме того, в данном случае операция + должна вернуть какой-то результат, чтобы присвоить его объекту c3. Мы возвращаем объект Counter. Возвращаемое значение присваивается переменной c3.

Заметьте, мы перегрузили операцию +, но не перегружали операцию =! Конечно же нужно добавить этот метод к классу Counter:


Counter operator= (Counter t)
{
Counter assign;
counter = t.counter;
assign.counter = t.counter;
return assign;
}


Внутри метода мы создали дополнительную переменную assign. Данная переменная используется, чтобы можно было работать вот с таким кодом:


Counter c1(5),c2,c3;
c3 = c2 = c1;


Хотя, для возвращаемого значения можно воспользоваться и более элегантными способами, с которыми мы вскоре познакомимся.