Выбрать главу

    Press any key to continue...

Обратите внимание: сообщение от конструктора StudentId появилось раньше, чем сообщение от конструктора Student. ( Поскольку у нас все конструкторы выводят информацию на экран, вы можете решить, что они всегда должны поступать подобным образом. На самом деле подавляющее большинство конструкторов работают "молча". )

_________________

205 стр. Глава 17. Аргументация конструирования

Если программист не обеспечит свой класс конструктором, то конструктор по умолчанию, созданный С++, вызовет конструкторы всех данных-членов для их инициализации. То же касается и уничтожения объекта. Деструктор класса автоматически вызывает деструкторы всех данных-членов ( у которых они определены ).

Теперь мы знаем, что будет с конструктором по умолчанию. Но что, если мы захотим вызвать другой конструктор? Куда в этом случае нужно поместить объект? Я имею в виду следующее: представьте себе, что вместо автоматической генерации идентификатора студента, необходимо передать его конструктору Student, который в свою очередь, должен передать его конструктору StudentId.

«Для начала я покажу вам способ, который работать не будет. ( Здесь приведена только существенная для понимания часть кода — полностью программа ConstructSeparateID.cpp находится на прилагаемом компакт-диске . )»

[Диск]

    class Student

    {

    public :

        Student( char *pName = "no name" , int ssId = 0 )

        {

            cout << "Конструктор Student( " << pName

                  << " )" << endl ;

            strncpy( name , pName , MAXNAMESIZE ) ;

            name[ MAXNAMESIZE - 1 ] = '\0' ;

            semesterHours = 0 ;

            gpa = 0.0 ;

            /* Вот это можно и не пытаться делать - толку не будет */

            StudentId id( ssId ) ;

        }

    protected :

        char name[ MAXNAMESIZE ] ;

        StudentId id ;

    } ;

Конструктор класса StudentId был переписан так, чтобы он мог принимать внешнее значение ( значение по умолчанию необходимо для того, чтобы приведённый фрагмент откомпилировался без ошибок, которые появятся в противном случае; почему — станет понятно чуть позже ). Внутри конструктора Student программист ( т.е. я ) попытался невиданным доселе способом сконструировать объект id класса StudentId.

Если вы внимательно посмотрите на сообщения, которые выдаются в результате работы этой программы, то поймёте, в чём проблема.

 

    Присвоение id 0

    Конструктор Student( Chester )

    Присвоение id 1234

    Деструктор id 1234 

    Сообщение из функции main( )

    Press any key to continue...

    Деструктор id 0

Первая проблема заключается в том, что конструктор класса StudentId вызывается дважды: сначала с нулём и только затем с ожидаемым числом 1234. Кроме того, объект с идентификатором 1234 ликвидируется перед выводом сообщения от main( ). Очевидно, объект класса StudentId ликвидируется внутри конструктора класса Student.

_________________

206 стр. Часть 3. Введение в классы

Объяснить такое странное поведение программы довольно просто. Член id уже существует к моменту перехода управления к телу конструктора Student. Поэтому вместо инициализации уже существующего члена id объявление в последней строке конструктора Student вызывает создание локального объекта с таким же именем. Этот локальный объект и уничтожается при выходе из конструктора.

«Очевидно, нужен некий механизм конструирования не нового объекта, а уже существующего. Этот механизм должен работать перед открытием фигурной скобки конструктора. Для этого в С++ определена конструкция, использованная в программе ConstructDataMember

[Диск]

    //

    /* ConstructDataMember — передача параметра */

    /*                      конструктору члена */

    //