Каждый класс определяет, как могут быть инициализированы объекты его типа. Класс контролирует инициализацию объекта за счет определения одной или нескольких специальных функций-членов, известных как конструкторы (constructor). Задача конструктора — инициализировать переменные-члены объекта класса. Конструктор выполняется каждый раз, когда создается объект класса.

В этом разделе рассматриваются основы определения конструкторов. Конструкторы — удивительно сложная тема. На самом деле мы сможем больше сказать о конструкторах в разделах 7.5, 15.7 и 18.1.3, а также в главе 13.

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

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

Синтезируемый стандартный конструктор

Хотя в нашем классе Sales_data не определено конструкторов, использующие его программы компилировались и выполнялись правильно. Например, программа из раздела 7.1.1 определяла два объекта класса Sales_data:

Sales_data total; // переменная для хранения текущей суммы

Sales_data trans; // переменная для хранения данных следующей

                  // транзакции

Естественно, возникает вопрос: как инициализируются объекты total и trans?

Настолько известно, инициализатор для этих объектов не предоставлялся, поэтому они инициализируются значением по умолчанию (см. раздел 2.2.1). Классы сами контролируют инициализацию по умолчанию, определяя специальный конструктор, известный как стандартный конструктор (default constructor). Стандартным считается конструктор, не получающий никаких аргументов.

Как будет продемонстрировано, стандартный конструктор является особенным во многом, например, если класс не определяет конструкторы явно, компилятор сам определит стандартный конструктор неявно.

Созданный компилятором конструктор известен как синтезируемый стандартный конструктор (synthesized default constructor). У большинства классов этот синтезируемый конструктор инициализирует каждую переменную-член класса следующим образом:

• Если есть внутриклассовый инициализатор (см. раздел 2.6.1), он и используется для инициализации члена класса.

• В противном случае член класса инициализируется значением по умолчанию (см. раздел 2.2.1).

Поскольку класс Sales_data предоставляет инициализаторы для переменных units_sold и revenue, синтезируемый стандартный конструктор использует данные значения для инициализации этих членов. Переменная bookNo инициализируется значением по умолчанию, т.е. пустой строкой.

Некоторые классы не могут полагаться на синтезируемый стандартный конструктор

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

Компилятор создает стандартный конструктор автоматически, только если в классе не объявлено никаких конструкторов.

Вторая причина для определения стандартного конструктора в том, что у некоторых классов синтезируемый стандартный конструктор работает неправильно. Помните, что определенные в блоке объекты встроенного или составного типа (такого как массивы и указатели) без инициализации имеют неопределенное значение (см. раздел 2.2.1). Это же относится к не инициализированным членам встроенного типа. Поэтому классы, у которых есть члены встроенного или составного типа, должны либо инициализировать их в классе, либо определять собственную версию стандартного конструктора. В противном случае пользователи могли бы создать объекты с членами, значения которых не определены.

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

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

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