Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Бьерн Страуструп C++.doc
Скачиваний:
12
Добавлен:
07.11.2018
Размер:
2.45 Mб
Скачать

1.4.1 Инициализация и удаление

Когда представление типа скрыто, необходимо дать пользователю средства для инициализации переменных этого типа. Простейшее решение – до использования переменной вызывать некоторую функцию для ее инициализации.

Например:

class vector

{

// ...

public:

void init ( init size ); // вызов init () перед первым

// использованием объекта vector

// ...

};

void f ()

{

vector v;

// пока v нельзя использовать

v.init ( 10 );

// теперь можно

}

Но это некрасивое и чреватое ошибками решение. Будет лучше, если создатель типа определит для инициализации переменных некоторую специальную функцию. Если такая функция есть, то две независимые операции размещения и инициализации переменной совмещаются в одной (иногда ее называют инсталляцией или просто построением). Функция инициализации называется конструктором. Конструктор выделяется среди всех прочих функций данного класса тем, что имеет такое же имя, как и сам класс. Если объекты некоторого типа строятся нетривиально, то нужна еще одна дополнительная операция для удаления их после последнего использования. Функция удаления в С++ называется деструктором. Деструктор имеет то же имя, что и его класс, но перед ним стоит символ ~ (в С++ этот символ используется для операции дополнения). Приведем пример:

class vector

{

int sz; // число элементов

int * v; // указатель на целые

public:

vector ( int ); // конструктор

~vector (); // деструктор

int& operator [] ( int index ); // операция индексации

};

Конструктор класса vector можно использовать для контроля над ошибками и выделения памяти:

vector::vector ( int s )

{

if ( s <= 0 )

error ( "недопустимый размер вектора" );

sz = s;

v = new int [ s ]; // разместить массив из s целых

}

Деструктор класса vector освобождает использовавшуюся память:

vector::~vector ()

{

delete [] v; // освободить массив, на который

// настроен указатель v

}

От реализации С++ не требуется освобождения выделенной с помощью new памяти, если на нее больше не ссылается ни один указатель (иными словами, не требуется автоматическая "сборка мусора"). В замен этого можно без вмешательства пользователя определить в классе собственные функции управления памятью. Это типичный способ применения конструкторов и деструкторов, хотя есть много не связанных с управлением памятью применений этих функций (см., например, $$9.4).

1.4.2 Присваивание и инициализация

Для многих типов задача управления ими сводится к построению и уничтожению связанных с ними объектов, но есть типы, для которых этого мало. Иногда необходимо управлять всеми операциями копирования. Вернемся к классу vector:

void f ()

{

vector v1 ( 100 );

vector v2 = v1; // построение нового вектора v2,

// инициализируемого v1

v1 = v2; // v2 присваивается v1

// ...

}

Должна быть возможность определить интерпретацию операций инициализации v2 и присваивания v1. Например, в описании:

class vector

{

int * v;

int sz;

public:

// ...

void operator = ( const vector & ); // присваивание

vector ( const vector & ); // инициализация

};

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

void vector::operator = ( const vector & a )

// контроль размера и копирование элементов

{

if ( sz != a.sz )

error ( "недопустимый размер вектора для =" );

for ( int i = 0; i < sz; i++ ) v [ i ] = a.v [ i ];

}

Поскольку эта операция использует для присваивания "старое значение" вектора, операция инициализации должна задаваться другой функцией, например, такой:

vector::vector ( const vector & a )

// инициализация вектора значением другого вектора

{

sz = a.sz; // размер тот же

v = new int [ sz ]; // выделить память для массива

for ( int i = 0; i < sz; i++ ) //копирование элементов

v [ i ] = a.v [ i ];

}

В языке С++ конструктор вида T(const T&) называется конструктором копирования для типа T. Любую инициализацию объектов типа T он выполняет с помощью значения некоторого другого объекта типа T. Помимо явной инициализации конструкторы вида T(const T&) используются для передачи параметров по значению и получения возвращаемого функцией значения.