Страница 8 из 48
Конструкторы. Основные свойства Сначала несколько форм Бэкуса-Наура. Объявление ::= ОбъявлениеФункции ::= ОпределениеФункции ::= ***** ОбъявлениеФункции ::= [СписокСпецификаторовОбъявления] Описатель [СпецификацияИсключения]; ОпределениеФункции ::= [СписокСпецификаторовОбъявления] Описатель [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;
и т.д., недопустимо. Возвращаемое значение специфицируется по типу, а как раз про тип возвращаемого конструктором значения в объявлении конструктора ничего и не сказано. Поэтому то, что обычно называется выражением явного вызова конструктора, вызовом, по сути, не является. |