Как и в случае с объектами-членами, вам может понадобиться передавать аргументы конструктору базового класса. Это делается почти так же, как и изученная ранее передача аргументов конструктору объекта-члена ( смотрите приведённый ниже пример ).

    GraduateStudent( char *pName , Advisor&adv , float qG=0.0 )

        :Student( pName ) , advisor( adv ) , qualifierGrade(qG)

    {

        /* Код конструктора */

    }

В этом примере конструктор класса GraduateStudent вызывает конструктор Student, передавая ему аргумент pName. Базовый класс конструируется до любых объектов-членов, а значит, конструктор класса Student вызывается перед конструктором Advisor. И только после конструктора члена Advisor начинает работу конструктор GraduateStudent.

В случае, когда в подклассе не указан явный вызов конструктора базового класса, вызывается конструктор по умолчанию базового класса. Таким образом, в следующем коде базовый класс Pig конструируется до членов LittlePig, несмотря на то, что конструктор LittlePig не делает явного вызова конструктора Pig.

    class Pig

    {

    public :

        Pig( ) : pHouse( 0 ) { }

    protected :

        House* pHouse ;

    } ;

    class LittlePig : public Pig

    {

    public :

        LittlePig( float volStraw , int numSticks , int numBricks )

            : straw( volStraw ) , sticks( numSticks ) , bricks( numBricks )

        { }

    protected :

        float straw ;

        int sticks ;

        int bricks ;

    } ;

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

_________________

237 стр. Глава 20. Наследование классов

<p id="chapter20.2.3"><strong><emphasis>Деструкция подкласса...238</emphasis></strong></p>

Следуя правилу о том, что деструкторы вызываются в порядке, обратном вызову конструкторов, первым вызывается деструктор GraduateStudent. После того как он выполнит свою работу, управление передаётся деструктору класса Advisor, а затем деструктору Student. Если бы Student был наследником класса Person, его деструктор получил бы управление после деструктора Student.

И это логично. Блок памяти сначала преобразуется в объект Student, а уже затем конструктор для GraduateStudent превращает этого студента в аспиранта. Деструктор же просто выполняет этот процесс в обратном направлении.

<p id="chapter20.3"><strong>►Отношение СОДЕРЖИТ...238</strong></p>

Обратите внимание, что класс GraduateStudent включает в себя члены классов Student и Advisor, однако он включает их по-разному. Определяя данные-члены класса Advisor, вы знаете, что класс Student содержит внутри все данные-члены класса Advisor, но вы не можете сказать, что GraduateStudent ЯВЛЯЕТСЯ Advisor. Однако вы можете сказать, что GraduateStudent СОДЕРЖИТ Advisor. Какая разница между этим отношением и наследованием?

Используем в качестве примера автомобиль. Вы можете логически определить автомобиль как подкласс транспортных средств, а значит, он будет наследовать свойства остальных транспортных средств. С другой стороны, автомобиль содержит мотор. Если вы покупаете автомобиль, то покупаете и мотор ( если, конечно, вы не покупаете бывшую в употреблении машину там же, где я купил свою кучу металлолома ).

Если друзья пригласят вас приехать на воскресный пикник на новой машине и вы приедете на ней, никто не будет удивлён ( даже если вы явитесь на мотоцикле ), поскольку автомобиль ЯВЛЯЕТСЯ транспортным средством. Но если вы появитесь на своих двоих, неся в руках мотор, друзья решат, что вы попросту издеваетесь над ними, поскольку мотор не является транспортным средством, так как не имеет некоторых важных свойств, присущих транспортным средствам.

В аспекте программирования связь типа СОДЕРЖИТ достаточно очевидна. Разберём следующий пример:

    class Vehicle

    {

    } ;

    class Motor

    {

    } ;

    class Car : public Vehicle

    {

    public :

        Motor motor ;

    } ;

    void VehicleFn( Vehicle& v ) ;

    void motorFn( Motor& m ) ;

_________________

238 стр. Часть 4. Наследование

    int main( )

    {

        Car с ;

        VehicleFn( с ) ; /* Так можно вызвать */

        motorFn( c ) ; /* А так — нельзя */

        motorFn( с.motor ) ; /* Нужно вот так */

        return 0 ;

    }

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

Все книги серии Для чайников

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