Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Перегрузка префиксных операторов



 

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

returnType Operator op (параметры)

В данном случае ор — это перегружаемый оператор. Тогда для перегрузки оператора преинкремента используем функцию

void operator++ ()

Этот способ показан в листинге 10.8.

Листинг 10.8 Перегрузка оператора преинкремента

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

2: // Перегрузка оператора преинкремента в классе Counter

3:

4: int

5: #include < iostream.h>

6:

7: class Counter

8: {

9: public:

10: Counter();

11: ~Counter(){ }

12: int GetItsVal()const { return itsVal; }

13: void SetItsVal(int x) { itsVal = x; }

14: void Increment() { ++itsVal; >

15: void operator++ () < ++itsVal; }

16:

17: private:

18: int itsVal;

19:

20: };

21:

22: Counter:: Counter():

23: itsVal(0)

24: { }

25:

26: int main()

27: {

28: Counter i;

29: cout < < " The value of i is " < < i.GetItsVal() < < endl;

30: i.Increment();

31: i cout < < " The value of i is " < < i.GetItsVal() < < endl;

32: ++i;

33: cout < < " The value of i is " < < i.GetItsVal() < < endl;

34: return 0;

35: }

 

Результат:

The value of i is 0

The value of i is 1

The value of i is 2

 

Анализ: В строке 15 перегружается operator++, который затем используется в строке 32 в результате объект класса Counter получает функции, которые можно было ожидать судя по его названию. Далее объекту сообщаются дополнительные возможности, призванные повысить эффективность его использования, в частности возможность контроля за максимальным значением, которое нельзя превышать в ходе приращения.

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

Counter а = ++i;

В этой строке делается попытка создать новый объект класса Counter — а, которому присваивается приращенное значение переменной i. Хотя встроенный конструктор- копировщик поддерживает операцию присваивания, текущий оператор инкремента не возвращает объект класса Counter. Сейчас он возвращает пустое значение void. Невозможно присвоить значение void объекту класса Counter. (Невозможно создать что-то из ничего! )

 

Типы возвратов перегруженных функций операторов

 

Все, что нам нужно, — это возвратить объект класса Counter таким образом, чтобы ero можно было присвоить другому объекту класса Counter. Как это сделать? Один подход состоит в том, чтобы создать временный объект и возвратить его. Он показан в листинге 10.9.

Листинг 10.8. Возвращение временного объекта

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

2: // Возвращение временного объекта

3:

4: int

5: #include < iostream.h>

6:

7: class Counter

8: {

9: public:

10: Counter();

11: ~Counter(){ }

12: int GetItsVal()const { return itsVal; }

13: void SetItsVal(int x) { itsVal = x; }

14: void Increment() { ++itsVal; }

15: Counter operator++ ();

16:

17: private:

18: int itsVal;

19:

20: };

21:

22: Counter:: Counter():

23: itsVal(0)

24: { }

25:

26: Counter Counter:: operator++()

27: {

28: ++itsVal;

29: Counter temp;

30: temp.SetItsVal(itsVal);

31: return temp;

32: }

33:

34: int main()

35: {

36: Counter i;

37: cout < < " The value of i is " < < i.GetItsVal() < < endl;

38: i.Incrernent();

39: cout < < " The value of i is " < < i.GetItsVal() < < endl;

40: ++i;

41: cout < < " The value of i is " < < i.GetItsVal() < < endl;

42: Counter а = ++i;

43: cout < < " The value of a: " < < a.GetItsVal();

44: cout < < " and i: " < < i.GetItsVal() < < endl;

45: return 0;

46: }

 

Результат:

The value of i is 0

The value of i is 1

The value of i is 2

The value of a: 3 and i: 3

 

Анализ: В данной версии программы operator++ объявлен в строке 15 таким образом, что может возвращать объекты класса Counter. В строке 29 создается временный объект ternp, и ему присваивается значение текущего объекта Counter. Значение временной переменной возвращается и тут же, в строке 42, присваивается новому объекту а.

 

Возвращение безымянных временных объектов

 

В действительности нет необходимости присваивать имя временному объекту, как это было сделано в предыдущем листинге в строке 29. Если в классе Counter есть принимающий значение конструктор, то параметру этого конструктора можно просто присвоить значение возврата оператора инкремента. Эта идея реализована в листинге 10.10.

Листинг 10.10. Возвращение безымянного временного объекта

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

2: // Возвращение безымянного временного объекта

3:

4: int

5: #include < iostream.h>

6:

7: class Counter

8: {

9: public:

10: Counter();

11: Counter(int val);

12: ~Counter(){ }

13: int GetItsVal()const { return itsVal; }

14: void SetItsVal(int x) { itsVal = x; }

15: void Increment() { ++itsVal; }

16: Counter operator++ ();

17:

18: private:

19: int itsVal;

20:

21: };

22:

23: Counter:: Counter():

24: itsVal(0)

25: { }

26:

27: Counter:: Counter(intval):

28: itsVal(val)

29: { }

30:

31: CounterCounter:: operator++()

32: {

33: ++itsVal;

34: return Counter (itsVal);

35: }

36:

37: int main()

38: {

39: Counter i;

40: cout < < " The value of i is" < < i.GetItsVal() < < endl;

41: i.Increment();

42: cout < < " The value of i is" < < i.GetItsVal() < < endl;

43: ++i;

44: cout < < " The value of i is" < < i.GetItsVal() < < endl;

45: Counter a = ++i;

46: cout < < " The value of a: " < < a.GetItsVal();

47: cout < < " and i: " < < i.GetItsVal() < < endl;

48: return 0;

49: }

 

Результат:

The value of i is 0

The value of i is 1

The value of i is 2

The value of a: 3 and i: 3

 

Анализ: В строке 11 определен новый конструктор, который принимает значение типа int. Данный конструктор выполняется в строках с 27 по 29. Происходит инициализация переменной itsVal значением, переданным в параметре.

Выполнение оператора инкремента в данной программе упрощено. В строке 33 осуществляется приращение переменной itsVal. Затем в строке 34 создается временный объект класса Counter, которому присваивается значение переменной itsVal. Это значение затем возвращается как результат выполнения оператора инкремента.

Подобное решение выглядит более элегантно, но возникает вопрос, для чего вообще нужно создавать временные объекты. Напомним, что создание и удаление временного объекта в памяти компьютера требует определенных временных затрат. Кроме того, если объект i уже существует и имеет правильное значение, почему бы просто не возвратить его? Реализуем эту идею с помощью указателя this.

 

Использование указателя this

 

На прошлом занятии уже рассматривалось использование указателя this. Этот указатель можно передавать в функцию-член оператора инкремента точно так же, как в любую другую функцию-член. Указатель this связан с объектом i и в случае разыменовывания возвращает объект, переменная которого itsVal уже содержит правильное значение. В листинге 10.11 показано возвращение указателя this, что снимает необходимость создания временных объектов.

Листинг 10.11. Возвращение указателя this

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

2: // Возвращение указателя this

3:

4: int

5: #include < iostream.h>

6:

7: class Counter

8: {

9: public:

10: Counter();

11: ~Counter(){ }

12: int GetItsVal()const { return itsVal; }

13: void SetItsVal(int x) { itsVal = x; }

14: void Increment() { ++itsVal; }

15: const Counter& operator++ ();

16:

17: private:

18: int itsVal;

19:

20: };

21:

22: Counter:: Counter():

23: itsVal(0)

24: { };

25:

26: const Counter& Counter:: operator++()

27: {

28: ++itsVal;

29: return *this;

30: }

31:

32: int main()

33: {

34: Counter i;

35: cout < < " The value of i is " < < i.GetItsVal() < < endl;

36: i.Increment();

37: cout < < " The value of i is " < < i.GetItsVal() < < endl;

38: ++i;

39: cout < < " The value of i is " < < i.GetItsVal() < < endl;

40: Counter а = ++i;

41: cout < < " The value of a: " < < a.GetItsVal();

42: cout < < " and i: " < < i.GetItsVal() < < endl;

43: return 0;

44: }

 

Результат:

The value of i is 0

The value of i is 1

The value of i is 2

The value of a: 3 and i: 3

 

Анализ: Выполнение оператора приращения в строках с 26 по 30 заменено разыменовыванием указателя this и возвращением текущего объекта. В результате объект класса Counter присваивается новому объекту а этого же класса. Как уже отмечалось выше, если объект класса Counter требует выделения памяти, необходимо заместить конструктор-копировщик. Но в данном случае конструктор- копировщик, заданный по умолчанию, отлично справляется со своими задачами.

Обратите внимание, что возвращаемое значение представляет собой ссылку класса Counter, благодаря чему отпадает необходимость в создании каких-либо дополнительных временных объектов. Ссылка задана как const, поскольку не должна меняться при использовании в функции.

 


Поделиться:



Популярное:

Последнее изменение этой страницы: 2017-03-08; Просмотров: 483; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.033 с.)
Главная | Случайная страница | Обратная связь