C++. Бархатный путь. Часть 2
Страница 8. Конструкторы. Основные свойства


Конструкторы. Основные свойства

Сначала несколько форм Бэкуса-Наура.

Объявление ::= ОбъявлениеФункции
::= ОпределениеФункции
::= *****
ОбъявлениеФункции ::=
[СписокСпецификаторовОбъявления]
Описатель
[СпецификацияИсключения];
ОпределениеФункции ::=
[СписокСпецификаторовОбъявления]
Описатель
[ctorИнициализатор]
[СпецификацияИсключения]
ТелоФункции
Описатель ::= Описатель ([СписокОбъявленийПараметров])
::= dИмя
dИмя ::= ИмяКласса

Используя это множество БНФ, можно строить объявления весьма странного вида:

ОбъявлениеФункции ::=
Описатель; ::=
Описатель (); ::=
dИмя (); ::=
ComplexType ();

Объявление… без спецификатора объявления.

ОпределениеФункции ::=
Описатель ТелоФункции ::=
Описатель () {} ::=
dИмя () {} ::=
ComplexType () {}

А это определение. Оно построено в соответствии с правилами построения функций. Не важно, что у него в теле нет ни одного оператора! Важно, что у него нет спецификатора объявления.

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

Отметим одно очень важное обстоятельство. Имя конструктора всегда совпадает с именем класса, членом которого является объявляемый конструктор. Ни одна функция-член класса не может называться именем класса. Ни одна функция-член класса не может быть объявлена и определена без спецификатора объявления. Характерное имя и отсутствие спецификации объявления отличает конструктор от функций-членов класса.

Отсутствие спецификаторов объявления означает, что конструктор не имеет абсолютно никакого отношения к вызову и возвращению значений. Конструктор не является функцией.

Так что объявления функций-членов класса ComplexType

void ComplexType();
ComplexType ComplexType();

не являются объявлениями конструктора. Для транслятора это всего лишь некорректные объявления функций-членов с пустыми списками параметров. Подобные объявления в классе ComplexType воспринимаются транслятором как ошибки.

А вот построенное нами объявление действительно является объявлением конструктора:

ComplexType();

И наше определение действительно является определением конструктора:

ComplexType(){}

Это ничего, что конструктор такой простой, зато он от начала и до конца правильный!

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

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

ComplexType(double rePar, double imPar); /* Объявление… */
ComplexType(double rePar, double imPar){/*…*/} /*Определение…*/

И ещё один вариант конструктора для класса ComplexType - на этот раз с одним параметром (его помощью, например, можно задавать значение мнимой части):

ComplexType(double imPar); /* Объявление… */
ComplexType(double imPar){/*…*/} /*Определение…*/

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

Отсутствие спецификации возвращаемого значения не означает запрета на использование оператора return в теле конструктора. В конце концов, это всего лишь оператор перехода. Но использование этого оператора в сочетании с выражением, задающим возвращаемое значение, например,

return NULL;
либо
return MyVal;
либо
return 125;

и т.д., недопустимо. Возвращаемое значение специфицируется по типу, а как раз про тип возвращаемого конструктором значения в объявлении конструктора ничего и не сказано. Поэтому то, что обычно называется выражением явного вызова конструктора, вызовом, по сути, не является.

 
Следующая статья »