Вход/Регистрация
Программирование. Принципы и практика использования C++ Исправленное издание
вернуться

Страуструп Бьерн

Шрифт:

Если класс обладает ресурсами, то он должен иметь деструктор. Ресурс — это то, что вы “где-то взяли” и должны вернуть, когда закончите его использовать. Очевидным примером является память, выделенная с помощью оператора new, которую вы должны освободить, используя оператор
delete
или
delete[]
. Для хранения своих элементов наш класс vector требует память, поэтому он должен ее вернуть; следовательно, он должен иметь деструктор. Другие ресурсы, которые используются в более сложных программах, — это файлы (если вы открыли файл, то должны его закрыть), блокировки (locks), дескрипторы потоков (thread handles) и двунаправленные каналы (sockets), используемые для обеспечения взаимосвязи между процессами и удаленными компьютерами.

Другой признак того, что в классе необходим деструктор, — это наличие членов класса, которые являются указателями или ссылками. Если одним из членов класса является указатель или ссылка, скорее всего, в нем требуются деструктор и операции копирования.

Класс, который должен иметь деструктор, практически всегда требует наличия копирующего конструктора и копирующего присваивания. Причина состоит в том, что если объект обладает ресурсом (и имеет указатель — член класса, ссылающийся на это ресурс), то копирование по умолчанию (почленное поверхностное копирование) почти наверняка приведет к ошибке. Классическим примером является класс
vector
.

Если производный класс должен иметь деструктор, то базовый класс должен иметь виртуальный деструктор (см. раздел 17.5.2).

18.3.1. Явные конструкторы

Конструктор, имеющий один аргумент, определяет преобразование типа этого аргумента в свой класс. Это может оказаться очень полезным. Рассмотрим пример.

class complex {

public:

complex(double); // определяет преобразование double в complex

complex(double,double);

// ...

};

complex z1 = 3.18; // OK: преобразует 3.18 в (3.18,0)

complex z2 = complex(1.2, 3.4);

Однако неявные преобразования следует применять скупо и осторожно, поскольку они могут вызвать неожиданные и нежелательные эффекты. Например, наш класс
vector
, определенный выше, имеет конструктор, принимающий аргумент типа
int
. Отсюда следует, что он определяет преобразование типа
int
в класс
vector
. Рассмотрим пример.

class vector {

// ...

vector(int);

// ...

};

vector v = 10; // создаем вектор из 10 элементов типа double

v = 20; // присваиваем вектору v новый вектор

// из 20 элементов типа double to v

void f(const vector&);

f(10); // Вызываем функцию f с новым вектором,

// состоящим из 10 элементов типа double

Кажется, мы получили больше, чем хотели. К счастью, подавить такое неявное преобразование довольно просто. Конструктор с ключевым словом
explicit
допускает только обычную семантику конструирования и не допускает неявные преобразования. Рассмотрим пример.

class vector {

// ...

explicit vector(int);

// ...

};

vector v = 10; // ошибка: преобразования int в vector нет

v = 20; // ошибка: преобразования int в vector нет

vector v0(10); // OK

void f(const vector&);

f(10); // ошибка: преобразования int в vector нет

f(vector(10)); // OK

Для того чтобы избежать неожиданных преобразований, мы — и стандарт языка — потребовали, чтобы конструктор класса

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

118.3.2. Отладка конструкторов и деструкторов

Конструкторы и деструкторы вызываются в точно определенных и предсказуемых местах программы. Однако мы не всегда пишем явные вызовы, например
vector(2)
; иногда мы пишем объявление объекта класса
vector
, передаем его как аргумент функции по значению или создаем в свободной памяти с помощью оператора
new
. Это может вызвать замешательство у людей, думающих в терминах синтаксиса. Не существует синтаксической конструкции, которая осуществляла бы диспетчеризацию вызовов конструкторов. О конструкторах и деструкторах проще думать следующим образом.

  • Читать дальше
  • 1
  • ...
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: