Файл: Pobegaylo_A._C_Cplus_dlya_studenta.pdf

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

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

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

Добавлен: 13.12.2020

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

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

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

Глава 15. Конструкторы и деструкторы 

201 

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

class Demo 

   unsigned size; 
public: 
   int* p; 
   // конструкторы 
   Demo(unsigned n): size(n), p(new int[size]) {} 
   Demo(const Demo& d); 
   // деструктор 
   ~Demo() { delete[] p; } 
}; 
// реализация конструктора копирования 
Demo::Demo(const Demo& d): size(d.size), p(new int[size]) 

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

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

  Demo d(3); 
  d.p[0] = 0; 
  d.p[1] = 1; 
  Demo c(d);  // вызывается конструктор копирования 

Конструктор копирования вызывается неявно в трех случаях: 

 

при передаче объекта в тело функции по значению; 

 

при возврате объекта из функции по значению; 

 

при инициализации объекта другим объектом этого же класса 
при помощи оператора присваивания. 


background image

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

202 

Например, в следующем примере вызывается конструктор копи-
рования, а не оператор присваивания: 

  Demo d(3); 
  d.p[0] = 0; 
  d.p[1] = 1; 
  Demo c = d;  // вызывается конструктор копирования 

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

private

15.5. Явный вызов конструкторов 

Конструктор может вызываться явно в двух случаях: 

 

в списке инициализации; 

 

в выражении. 

Во  втором  случае  конструктор  рассматривается  как  оператор, 
возвращающий  анонимный  константный  объект  соответствую-
щего типа. Например: 

  int n = 1 + int(1.7);  // n = 2 

Отсюда следует, что конструкторы могут использоваться в выра-
жения для явного преобразования типов данных. 
Конструктор с одним параметром рассматривается компилятором 
как  определенный  пользователем  оператор  преобразования  ти-
пов.  То  есть  компилятор  может  использовать  этот  конструктор 
для неявного преобразования типов в выражении. 
В  листинге  15.3  приведен  пример  использования  конструктора 
с одним параметром как оператора преобразования типа. 

Листинг 15.3. Использование конструктора в качестве оператора 

преобразования типа 

#include <iostream> 
using namespace std; 


background image

Глава 15. Конструкторы и деструкторы 

203 

struct Demo 

  int n; 
public: 
  Demo(int _n = 0): n(_n) {} 
  operator+=(const Demo& d) { n += d.n; } 
}; 
 
int main() 

  Demo d; 
  d += 10; 
  cout << d.n << endl; 
 
  return 0; 

Чтобы  запретить  такое  использование  конструктора  с  одним па-
раметром,  этот  конструктор  объявляется  как 

явный

  при  помощи 

спецификатора 

explicit

. Например: 

struct Demo 

  int n; 
public: 
  explicit Demo(int _n = 0): n(_n) {} 
  operator+=(const Demo& d) { n += d.n; } 
}; 

Тогда приведенный ниже оператор присваивания вызовет ошиб-
ку компиляции. 

  Demo d; 
  d += 10;  // ошибка компиляции 

15.6. Деструкторы 

Деструктор

 — это функция-член класса, имя которой начинает-

ся с символа 

~

, за которым без пробелов следует имя класса. Де-

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

неявно  при  уничтожении 


background image

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

204 

объекта

.  Деструктор  предназначен  для  освобождения  ресурсов, 

захваченных во время жизни объекта. 
Например, в классе 

Demo

 из 

разд. 15.4

 деструктор был  определен 

следующим образом: 

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

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

 

деструктор не может иметь параметров; 

 

деструктор не может возвращать значения; 

 

деструктор не может быть объявлен с квалификаторами 

const

 

или 

volatile

 

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

static

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

 

для 

static

 объектов при завершении программы; 

 

для  локальных  объектов  при  выходе  из  блока,  в  котором  эти 
объекты определены; 

 

при применении оператора 

delete

 к указателю на объект; 

 

при раскрутке стека во время обработки исключения. 

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

new

. В других случаях вы-

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


background image

Глава 15. Конструкторы и деструкторы 

205 

15.7. Исключения в деструкторах 

Если во время раскрутки стека 

(см. разд. 13.5)

 выброшено новое 

исключение,  то  механизм  обработки  исключений  вызывает 
функцию 

terminate

,  которая  завершает  программу  посредством 

вызова  функции 

abort

.  Поэтому  выбрасывать  исключения  из  

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

uncaught_exception

,  которая  определена  в  заголовочном  файле 

exception. Использование этой функции рассмотрено в 

разд. 36.6

 


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