Конструктор инициализирующий – это конструктор, который вызывается с одним или несколькими аргументами.
При использовании инициализирующего конструктора происходит инициализация переменных-членов аргументами конструктора. Если какая-то из закрытых переменных-членов осталась неинициализирована, то компилятор вызывает для нее конструктор по умолчанию, если он существует, в противном случае он выдает ошибку.
Рассмотрим простой пример, демонстрирующий использование инициализирующего конструктора:
class Stack
{
char * s;
int max_len;
int top;
public:
Stack(int); // Конструктор инициализирующий
// …
};
inline Stack :: Stack(int size)
{
s = new char[size];
max_len = size;
top = 0;
}
Конструктор класса Stack выполняет инициализацию член-данных max_len и top, а также указателя s. Указатель s инициализируется адресом динамической области, полученной операцией new. Размер области определяется аргументом, который принимает конструктор. Каждый раз при создании объекта типа Stack будет автоматически вызываться этот конструктор:
Stack s1(100); // Создание объекта с помощью конструктора
Stack * р = new Stack(50); // Создание объекта операцией new
Если у класса есть конструктор, при определении объекта он всегда будет вызываться, даже если он явно не указан, поэтому аргументы конструктору в той или иной форме должны быть заданы:
Stack s3(512); // Краткая форма (неявный вызов конструктора)
Stack s4; // Ошибка, не задан аргумент для конструктора
Наличие конструктора в классе Stack вынуждает при определении объекта этого класса указывать аргументы.
В следующем примере используются два конструктора, реализующие различные способы инициализации закрытых элементов класса:
class Stack
{
char * s;
int max_len;
int top;
public:
Stack(int); // Конструктор 1
Stack(char *, int); // Конструктор 2
// …
};
Stack :: Stack(int size)
{
s = new char [size];
max_len = size;
top = 0;
}
Stack :: Stack(char * p, int size)
{
s = p;
max_len = size;
top = 0;
}
В классе Stack определены два конструктора, что дает возможность объявить объект класса Stack двумя способами:
1) указав размер стека (конструктор Stack (int));
2) указав адрес ранее распределенной области и ее размер (конструктор Stack (char * p, int size)).
Во втором случае динамическая память для стека не будет распределяться операцией new, а будет использоваться память, адрес которой конструктор получит в качестве аргумента. Наличие такого конструктора – плохой стиль программирования, поскольку область стека напрямую доступна в программе и может там изменяться.
Динамическая память, получаемая первым конструктором, в программе напрямую недоступна: указатель s "скрыт" в части private класса Stack.
Подчеркнем, что собственно конструктор не резервирует память для объекта. Он выполняет только те операции, которые записаны в теле функции-конструктора. Таким образом, хотя конструктор Stack (int) и получает область динамической памяти по операции new, в результате его действия будет инициализирован лишь указатель s и установлено значение член-данных max_len и top. Память же для объекта класса Stack, как и для объектов встроенных типов, отводится механизмом его объявления.