C++ для начинающих - страница 15

стр.

>


>// инициализация элементов массива

>for (int ix=0; ix_size; ++ix)

>ia[ix] = 0;

>}


Это определение содержит несколько упрощенный вариант реализации. Мы не позаботились о том, чтобы попытаться избежать возможных ошибок во время выполнения. Какие ошибки возможны? Во-первых, оператор new может потерпеть неудачу при выделении нужной памяти: в реальной жизни память не бесконечна. (В разделе 2.6 мы увидим, как обрабатываются подобные ситуации.) А во-вторых, параметр sz из-за небрежности программиста может иметь некорректное значение, например нуль или отрицательное.

Что необычного мы видим в таком определении конструктора? Сразу бросается в глаза первая строчка, в которой использована операция разрешения области видимости (::):


>IntArray::IntArray(int sz);


Дело в том, что мы определяем нашу функцию-член (в данном случае конструктор) вне тела класса. Для того чтобы показать, что эта функция на самом деле является членом класса IntArray, мы должны явно предварить имя функции именем класса и двойным двоеточием. (Подробно области видимости разбираются в главе 8; области видимости применительно к классам рассматриваются в разделе 13.9.)

Второй конструктор класса IntArray инициализирует объект IntArray значениями элементов массива встроенного типа. Он требует двух параметров: массива встроенного типа со значениями для инициализации и размера этого массива. Вот как может выглядеть создание объекта IntArray с использованием данного конструктора:


>int ia[10] = {0,1,2,3,4,5,6,7,8,9};

>IntArray iA3(ia,10);


Реализация второго конструктора очень мало отличается от реализации конструктора по умолчанию. (Как и в первом случае, мы пока опустили обработку ошибочных ситуаций.)


>IntArray::IntArray (int *array, int sz)

>{

>// инициализация членов данных

>_size = sz;

>ia = new int[_size];


>// инициализация элементов массива

>for (int ix=0; ix_size; ++ix)

>ia[ix] = array[ix];

>}


Третий конструктор называется копирующим конструктором. Он инициализирует один объект типа IntArray значением другого объекта IntArray. Такой конструктор вызывается автоматически при выполнении следующих инструкций:


>IntArray array;

>// следующие два объявления совершенно эквивалентны:

>IntArray ia1 = array;

>IntArray ia2 (array);


Вот как выглядит реализация копирующего конструктора для IntArray, опять-таки без обработки ошибок:


>IntArray::IntArray (const IntArray rhs )

>{

>// инициализация членов данных

>_size = rhs._size;

>ia = new int[_size];


>// инициализация элементов массива

>for (int ix=0; ix_size; ++ix)

>ia[ix] = rhs.ia[ix];

>}


В этом примере мы видим еще один составной тип данных – ссылку на объект, которая обозначается символом . Ссылку можно рассматривать как разновидность указателя: она также позволяет косвенно обращаться к объекту. Однако синтаксис их использования различается: для доступа к члену объекта, на который у нас есть ссылка, следует использовать точку, а не стрелку; следовательно, мы пишем rhs._size, а не rhs-_size. (Ссылки рассматриваются в разделе 3.6.)

Заметим, что реализация всех трех конструкторов очень похожа. Если один и тот же код повторяется в разных местах, желательно вынести его в отдельную функцию. Это облегчает и дальнейшую модификацию кода, и чтение программы. Вот как можно модернизировать наши конструкторы, если выделить повторяющийся код в отдельную функцию init():


>class IntArray {

>public:

>explicit IntArray (int sz = DefaultArraySize);

>IntArray (int *array, int array_size);

>IntArray (const IntArray rhs);

>// ...

>private:

>void init (int sz,int *array);

>// ...

>};


>// функция, используемая всеми конструкторами

>void IntArray::init (int sz,int *array)

>{

>_size = sz;

>ia = new int[_size];


>for (int ix=0; ix_size; ++ix)

>if ( !array )

>ia[ix] = 0;

>else

>ix[ix] = array[ix];

>}


>// модифицированные конструкторы

>IntArray::IntArray (int sz) { init(sz,0); }

>IntArray::IntArray (int *array, int array_size)

>{ init (array_size,array); }

>IntArray::IntArray (const IntArray rhs)

>{ init (rhs._size,rhs.ia); }


Имеется еще одна специальная функция-член – деструктор, который автоматически вызывается в тот момент, когда объект прекращает существование. Имя деструктора совпадает с именем класса, только в начале идет символ тильды (~). Основное назначение данной функции – освободить ресурсы, отведенные объекту во время его создания и использования. Применение деструкторов помогает бороться с трудно обнаруживаемыми ошибками, ведущими к утечке памяти и других ресурсов. В случае класса IntArray эта функция-член должна освободить память, выделенную в момент создания объекта. (Подробно конструкторы и деструкторы описаны в главе 14.) Вот как выглядит деструктор для IntArray: