Файл: Pobegaylo_A._C_Cplus_dlya_studenta.pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 13.12.2020

Просмотров: 4160

Скачиваний: 28

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

Глава 16. Перегрузка операторов 

211 

Оператор  присваивания  и  конструктор  копирования  обычно  со-

держат  много  общего кода.  Поэтому  в  этом  случае  часто  пишут 

отдельную, закрытую функцию, которая реализует этот код и вы-

зывается как в операторе присваивания, так и конструкторе копи-

рования. 
В  листинге  16.2  приведен  пример  класса,  для  которого  нужно 

обязательно  перегрузить  оператор  присваивания.  Этот  класс  яв-
ляется расширением класса 

Demo

, приведенного в 

разд. 15.4

Листинг 16.2. Определение класса с перегруженным оператором 

присваивания 

#if !defined DEMO 
#define DEMO 
class Demo 

  unsigned size; 
  void copy(const Demo& d);  // функция копирования 
public: 
  int* p; 
  // конструкторы 
  Demo(unsigned n): size(n), p(new int[size]) {} 
  Demo(const Demo& d); 
  // оператор присваивания 
  Demo& operator =(const Demo& d); 

  // деструктор 
  ~Demo() { delete[] p; } 
}; 
#endif 

В листинге 16.3 приведена реализация конструктора копирования 
и оператора присваивания для класса 

Demo

Листинг 16.3. Реализация оператора присваивания 

#include "Demo.h" 
// реализация функции копирования объектов 
void Demo::copy(const Demo& d) 


background image

Часть II. Язык программирования С++ 

212 


  for (unsigned i = 0; i < size; ++i) 
    p[i] = d.p[i]; 

// реализация конструктора копирования 
Demo::Demo(const Demo& d): size(d.size), p(new int[size]) 

  copy(d); 

// реализация оператора присваивания 
Demo& Demo::operator =(const Demo& d) 

  if (&d != this) 
  { 
    delete[] p;  // удаляем старый массив 
    size = d.size; 
    p = new int[size]; 
    copy(d);     // копируем 
  } 
  return *this; 

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

16.4. Составные операторы 
присваивания 

Составные  операторы  присваивания  также  могут  быть  пере- 
гружены  только  как  нестатические  члены  класса.  Перегружен- 
ные  составные  операторы  присваивания  имеют  следующий  про-
тотип: 

  имя_класса& operator @(const имя_класса&); 

Символ 

@

  обозначает  составной  оператор  присваивания.  Как  ви-

дим,  этот  прототип  аналогичен  прототипу  простого  оператора 


background image

Глава 16. Перегрузка операторов 

213 

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

Bool

Bool& Bool::operator +=(const Bool& b) 

  n ? n : n = b.n; 
  return *this; 

16.5. Оператор индексирования 

[ ]

 

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

[]

  перегружается  только  как  нестати-

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

  struct BadIndex {}; 
  class Coord 
  { 
    int x, y; 
  public: 
    Coord() {} 
    Coord(int _x, int _y): x(_x), y(_y) {} 
    int& operator [](const int& i) 
    { 
      switch (i) 
      { 
      case 0: return x; 
      case 1: return y; 
      default: throw BadIndex(); 
      } 
    } 


background image

Часть II. Язык программирования С++ 

214 

    const int& operator [](const int& i) const  
    { 
      switch (i) 
      { 
      case 0: return x; 
      case 1: return y; 
      default: throw BadIndex(); 
      } 
    } 
  }; 

16.6. Оператор вызова функции 

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

()

 должен иметь следующий прототип: 

  тип operator ()(список_параметров); 

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

объектом-функцией

 или 

функциональным объектом

В  листинге  16.4  приведен  пример  перегрузки  оператора  вызова 
функции. 

Листинг 16.4. Перегрузка оператора вызова функции 

#include <iostream> 
using namespace std; 
struct Inc 

  int& operator()(int& n) { return ++n; } 
}; 
int main() 

  Inc inc; 
  int n = 1; 


background image

Глава 16. Перегрузка операторов 

215 

  inc(n); 
  cout << inc(n) << endl;    // печатает 3 
 
  return 0; 

16.7. Оператор доступа  
к членам класса 

Оператор  доступа  к  членам  класса 

->

  должен  быть  перегружен 

как нестатический член класса без параметров, а также обеспечи-
вать  семантику  указателя  потому,  что  для  объекта 

x

  выражение  

x->m

 интерпретируется компилятором как: 

  (x.operator->()) -> m 

Перегрузка  оператора 

->

  используется  для  создания  указателей 

на объекты с дополнительными возможностями. 
Например, в листинге 16.5 реализован класс 

ptr

, который не по-

зволяет  создавать  неинициализированные  указатели  на  объекты 
типа 

int

. Кроме того, в этой программе приведены примеры пе-

регрузки операторов определения адреса и разыменования. 

Листинг 16.5. Перегрузка операторов доступа к членам класса,  
определения адреса и разыменования 

#include <iostream> 
using namespace std; 
struct Demo 

  int n; 
  int what() { return n; } 
}; 
class ptr 

  Demo* p; 
public: 
  ptr(Demo& d): p(&d) {} 


Смотрите также файлы