Чтение онлайн

ЖАНРЫ

Освой самостоятельно С++ за 21 день.

Либерти Джесс

Шрифт:

Количество операндов, которыми может манипулировать оператор, — важная характеристика каждого оператора. Различают операторы, используемые с одним операндом (например, оператор инкремента: myValue++), и операторы, для работы которых необходимо указать два операнда (например, оператор суммирования: a+b). Сразу тремя операндами управляет только условный оператор ?, синтаксис использования которого показан в следующем примере: (а > b ? x : у).

Что можно перегружать

Возможность перегрузки операторов — это то новое средство программирования, предоставляемое C++, которое

наиболее широко используют (а часто и злоупотребляют им) начинающие программисты. Новичков захватывает азарт присвоения новых интересных функций самым обычным и заурядным операторам. В результате код программы может оказаться непонятным и нечитабельным даже для создателя, а не то что для другого программиста.

Безусловно, если в программе оператор + начнет осуществлять вычитание, а оператор * — суммирование, это может тешить самолюбие начинающего программиста, но профессионал никогда такого не допустит. Вполне можно понять желание использовать оператор + для конкатенации строк и символов, а оператор / для разделения строк, но такая перегрузка операторов таит в себе подводные рифы, на которые может совершенно неожиданно напороться программа во время выполнения. Возможно, было бы не плохо уделить больше внимания особенностям использования перегруженных операторов, но еще лучше начать с формулировки основных предостережений. Прежде всего следует помнить, что основная цель перегрузки операторов состоит в том, чтобы сделать программу эффективнее, а ее код проще и понятнее.

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

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

Оператор присваивания

 Четвертая, и последняя, функция, предоставляемая компилятором для работы с объектами, если, конечно, вы не задали никаких дополнительных функций, это функция оператора присваивания (operator=). Этот оператор используется всякий раз, когда нужно присвоить объекту новое значение, например:

CAT catOne(5,7);

CAT catTwo(3,4);

//...другие строки программы

catTwo = catOne

В данном примере создан объект catOne, переменной которого itsAge присвоено значение 5, а переменной itsWeigth — 7. Затем создается объект catTwo со значениями переменных соответственно 3 и 4.

Через некоторое время объекту catTwo присваиваются значения объекта catOne. Что произойдет, если переменная itsAge является указателем, и что происходит со старыми значениями переменных объекта catTwo?

Работа с переменными-членами, которые хранят свои значения в области динамической памяти, рассматривалась ранее при обсуждении использования конструктора- копировщика (см. также рис. 10.1 и 10.2).

В C++ различают поверхностное и глубинное копирование данных. При поверхностном копировании происходит передача только адреса от одной переменной к другой, в результате чего оба объекта указывают на одни и те же ячейки памяти. В случае глубинного копирования действительно происходит копирование значений переменных из одной области памяти в другую. Различия между этими методами копирования показаны

на рис. 10.3.

Все вышесказанное справедливо для присвоения данных. В случае использования оператора присваивания, процесс обмена данных протекает с некоторыми особенностями. Так, объект catTwo уже существует вместе со своими переменными, для каждой из которых выделены определенные ячейки памяти. В случае присвоения объекту новых значений предварительно необходимо освободить эти ячейки памяти. Что произойдет, если выполнить присвоение объекта catTwo самому себе:

catTwo = catTwo

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

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

Чтобы предупредить подобную ситуацию, ваш оператор присваивания прежде всего должен определить, не совпадают ли друг с другом объекты по обе стороны от оператора присваивания. Это можно осуществить с помощью указателя this, как показано в листинге 10.15.

Листинг 10.15. Оператор присваивания

1: // Листинг 10.15.

2: // Конструктор-копировщик

3:

4: #include <iostream.h>

5:

6: class CAT

7: {

8: public:

9: CAT; // конструктор по умолчанию

10: // конструктор-копировщик и деструктор пропущены!

11: int GetAge const { return *itsAge; }

12: int GetWeight const { return *itsWeight; }

13: void SetAge(int age) { *itsAge = age; }

14: CAT & operator=(const CAT &);

15:

16: private:

17: int *itsAge;

18: int *itsWeight;

19: };

20:

21: CAT::CAT

22: {

23: itsAge = new int;

24: itsWeight = new int;

25: *itsAge = 5;

26: *itsWeight = 9;

27: }

28:

29:

30: CAT & CAT::operator=(const CAT & rhs)

31: {

32: if (this == &rhs)

33: return *this;

34: *itsAge = rhs.GetAge;

35: *itsWeight = rhs.GetWeight;

36: return *this;

37: }

38:

39:

40: int main

41: {

42: CAT frisky;

43: cout << "frisky's age: " << frisky.GetAge << endl;

44: cout << "Setting frisky to 6...\n";

45: frisky.SetAge(6);

46: CAT whiskers;

47: cout << "whiskers' age: " << whiskers.GetAge << endl;

48: cout << "copying frisky to whiskers...\n";

49: whiskers = frisky;

50: cout << "whiskers' age: " << whiskers.GetAge << endl;

51: return 0;

52: }

Результат:

frisky's age: 5

Setting frisky to 6. . .

whiskers' age: 5

copying frisky to whiskers...

whiskers' age: 6

Анализ: В листинге 10.15 вновь используется класс CAT. Чтобы не повторяться, в данном коде пропущены объявления конструктора-копировщика и деструктора. В строке 14 объявляется оператор присваивания, определение которого представлено в строках 30—37.

Поделиться с друзьями: