Поведение перегруженных функций во время выполнения ничем не отличается от поведения обычных. Компилятор определяет нужную функцию и помещает в объектный код именно ее вызов. (В главе 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);
называется
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 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)