C++. Бархатный путь. Часть 2 - Определение и инициализация объекта-представителя класса
ОГЛАВЛЕНИЕ
Определение и инициализация объекта-представителя класса
Определение объекта предполагает выделение области памяти, достаточное для размещения данных-членов объекта и организацию ссылки на объект.
В C++ существует множество способов определения (создания) объектов.
В частности, объект может быть создан:
- как глобальная переменная,
- как локальная переменная,
- как элемент области активации при вызове функции,
- при явном обращении к конструктору,
- в результате выполнения выражения размещения,
- как временная переменная.
В каждом из этих случаев в определении объекта принимают участие конструкторы, передача управления которым при создании объекта обеспечивается транслятором, как правило, без участия программиста.
Особенности объявления конструктора в C++ и его свойства делают синтаксически неразличимыми выражения преобразования и обращения к конструктору. В ряде случаев можно утверждать, что передача управления конструктору ("вызов" конструктора) является лишь побочным эффектом выполнения выражения преобразования.
Для изучения свойств конструктора мы объявим новый класс - класс комплексных чисел. Это благодарный пример для изучения объектно-ориентированного программирования. В дальнейшем мы не раз будем обращаться к этому классу.
class ComplexType
{
public:
double real, imag;
/* Действительная и мнимая часть комплексного числа. */
};
/*Это было объявление класса, а сейчас - определения объекта.*/
ComplexType GlobalVal;
/* Как глобальная переменная.*/
void main ()
{
ComplexType MyVal;/* Как локальная переменная.*/
ComplexType *pVal = new(ComplexType);
/* В результате выполнения выражения размещения*/
}
Если объект создаётся в результате выполнения выражения размещения, он располагается в динамической памяти и остаётся безымянным, поскольку значениями выражений размещения является значение указателя на выделенную область памяти. В этом случае обращение к объекту возможно только по указателю, означенному в результате выполнения этого выражения.
В объявлении класса невозможно указать начальные значения данных-членов (это всё-таки объявление). И поэтому после создания объекта эти значения оказываются неопределёнными. Объекты приходится дополнительно инициализировать, специально присваивая значения данным-членам класса.
В принципе нет ничего предосудительного в поэтапном определении и модификации объектов. Для этого достаточно определить несколько управляющих функций-членов класса, которые можно вызывать "от имени новорожденного объекта" для задания соответствующих значений данным-членам класса. Однако в C++ существует возможность совмещения процесса определения и инициализации. Дело в том, что у оператора определения объекта сложная семантика. C++ позволяет совмещать обязательные работы по размещению объекта в памяти, выполняемые специальным программным кодом, который автоматически подставляется транслятором на стадии генерации и работы по инициализации значений данных-членов.
Для программиста это может означать только одно: он может самостоятельно включить собственные операторы в особый список операторов, после чего транслятор гарантирует, что эти операторы будут выполняться в нужное время. Нам остаётся выяснить, куда следует встраивать эти операторы, и когда они будут выполняться.
Тот самый список операторов, который выполняется при определении объекта, и называется конструктором.
Основное назначение конструктора - определение объектов. Если программист не вмешивается в процесс построения объекта, транслятор свмостоятельно формирует стандартный конструктор, который невидим для программиста. Как и когда он используется, и что при этом он делает - об этом известно только транслятору.
Программист может объявить и определить в классе собственные версии конструктора. Собственная версия конструктора - это собственная последовательность операторов. Эти операторы выполняются непосредственно после прогаммного кода, который обеспечивает регламентные работы по созданию объекта.
Существуют строгие правила оформления подобных альтернативных конструкторов, поскольку транслятор должен понимать, что он имеет дело именно с конструктором, а не с какой-либо функцией. Правилам построения и особенностям конструкторов посвящается следующий раздел.