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

    #include <iostream>

    using namespace std ;

    class Bed

    {

      public :

        Bed( ) { }

        void sleep( ) { cout << "Спим" << endl ; }

        int weight ;

    } ;

    class Sofa

    {

      public :

        Sofa( ) { }

        void watchTV( ) { cout << "Смотрим телевизор" << endl ; }

        int weight ;

    } ;

    /* SleeperSofa — диван-кровать */

    class SleeperSofa : public Bed , public Sofa

    {

      public :

        SleeperSofa( ) { }

        void foldOut( ) { cout << "Раскладываем диван-кровать"

                                << endl ; }

    } ;

    int main( int nNumberofArgs , char* pszArgs[ ] )

    {

            /* печать кириллицы, если Вы не установите программки gccrus.exe и g++rus.exe */

            setlocale ( LC_ALL , ".1251" ) ;

        SleeperSofa ss ;

        /* Посмотрим телевизор на диване... */

        ss.watchTV( ) ; /* Sofa::watchTV( ) */

        /* ...разложим его в кровать... */

        ss.foldOut( ) ; /* SleeperSofa::foldOut( ) */

        /* ...и ляжем спать */

        ss.sleep( ) ;

        /* Пауза для того, чтобы посмотреть на результат работы программы */

        system( "PAUSE" ) ; return 0 ;

    }

В этом примере класс SleeperSofa наследует оба класса — Bed и Sofa. Это видно из их наличия в объявлении класса SleeperSofa, который наследует все члены от обоих базовых классов. Таким образом, допустимы оба вызова — как ss.sleep( ), так и ss.watchTV( ). Вы можете использовать SleeperSofa и как Bed, и как Sofa. Кроме того, класс SleeperSofa имеет собственные члены, например foldOut( ). В результате мы получим следующий вывод программы:

    Смотрим телевизор

    Раскладываем диван-кровать

    Спим

    Press any key to continue...

_________________

299 стр. Глава 26. Множественное наследование 

►Устранение неоднозначностей множественного наследования...300

Будучи весьма мощной возможностью языка, множественное наследование может стать в то же время и источником проблем. Одну из них можно увидеть уже в предыдущем примере. Обратите внимание, что оба класса — Bed и Sofa — содержат член weight ( вес ). Это логично, потому что они оба имеют некоторый вполне измеримый вес. Вопрос: какой именно член weight наследует класс SleeperSofa?

Ответ прост: оба. Класс SleeperSofa наследует отдельный член Bed::weight и отдельный член Sofa::weight. Поскольку они оба имеют одно и то же имя, обращения к weight теперь являются двузначными, если только не указывать явно, к какому именно weight мы намерены обратиться. Это демонстрирует следующий фрагмент кода:

    #include <iostream>

    void fn( )

    {

        SleeperSofa ss ;

        cout << "Beс = "

             << ss.weight /* неправильно — какой именно вес? */

             << "\n" ;

    }

Теперь в программе нужно явно указывать, какая именно переменная weight нужна, используя для этого имя базового класса. Приведённый ниже пример вполне корректен.

    #include <iostream>

    void fn( )

    {

        SleeperSofa ss ;

        cout << "Вес дивана = "

             << ss.Sofa::weight /*укажем, какой именно вес */     

              << "\n" ;

    }

Хотя такое решение и устраняет ошибку, указание имени базового класса во внешнем приложении нежелательно: ведь при этом информация о внутреннем устройстве класса должна присутствовать за его пределами. В нашем примере функция fn( ) должна располагать сведениями о том, что класс SleeperSofa наследуется от класса Sofa. Такие конфликты имён невозможны при одиночном наследовании, но служат постоянным источником неприятностей при наследовании множественном.