Поведение перегруженных функций во время выполнения ничем не отличается от поведения обычных. Компилятор определяет нужную функцию и помещает в объектный код именно ее вызов. (В главе 9 подробно обсуждается механизм перегрузки.)

Итак, вернемся к нашему классу IntArray. Давайте определим для него три конструктора:

class IntArray {

public:

explicit IntArray (int sz = DefaultArraySize);

IntArray (int *array, int array_size);

IntArray (const IntArray rhs);

// ...

private:

static const int DefaultArraySize = 12;

}

Первый из перечисленных конструкторов

IntArray (int sz = DefaultArraySize);

называется конструктором по умолчанию, потому что он может быть вызван без параметров. (Пока не будем объяснять ключевое слово explicit.) Если при создании объекта ему задается параметр типа int, например

IntArray array1(1024);

то значение 1024 будет передано в конструктор. Если же размер не задан, допустим:

IntArray array2;

то в качестве значения отсутствующего параметра конструктор принимает величину DefaultArraySize. (Не будем пока обсуждать использование ключевого слова static в определении члена DefaultArraySize: об этом говорится в разделе 13.5. Скажем лишь, что такой член данных существует в единственном экземпляре и принадлежит одновременно всем объектам данного класса.)

Вот как может выглядеть определение нашего конструктора по умолчанию:

IntArray::IntArray (int sz)

{

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

_size = sz;

ia = new int[_size];

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

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)

Перейти на страницу:

Похожие книги