Чтение онлайн

на главную - закладки

Жанры

Шрифт:

Когда описывается производная struct, ее базовый класс по умолчанию является public базовым классом. То есть,

struct D : B (* ...

означает

class D : public B (* public: ...

Отсюда следует, что если вы не сочли полезным то сокртие данных, которое дают class, public и friend, вы можете просто не использовать эти ключевые слова и придерживаться struct. Такие средства языка, как функции члены, конструкторы и перегрузка операций, не зависят от механизма сокрытия даных.

Можно также объявить некоторые, но не все, открытые члны базового класса открытыми членами

производного класса. Например:

class manager : employee (* // ... public: // ... employee::name; employee::department; *);

Запись

имя_класса :: имя_члена ;

не вводит новый член, а просто делает открытый член бзового класса открытым для производного класса. Теперь name и department могут использоваться для manager'а, а salary и age – нет. Естественно, сделать закрытый член базового класса окрытым членом производного класса невозможно. Невозможно с помощью этой записи также сделать открытыми перегруженные имена.

Подытоживая, можно сказать, что вместе с предоставлением средств дополнительно к имеющимся в базовом классе, произвоный класс можно использовать для того, чтобы сделать средства (имена) недоступными для пользователя. Другими словами, с пмощью производного класса можно обеспечивать прозрачный, плупрозрачный и непрозрачный доступ к его базовому классу.

7.2.4 Указатели

Если производный класс derived имеет открытый базовый класс base, то указатель на derived можно присваивать перменной типа указатель на base не используя явное преобразовние типа. Обратное преобразование, указателя на base в указтель на derived, должно быть явным. Например:

class base (* /* ... */ *); class derived : public base (* /* ... */ *);

derived m; base* pb = amp;m; // неявное преобразование derived* pd = pb; // ошибка: base* не является derived* pd = (derived*)pb; // явное преобразование

Иначе говоря, объект производного класса при работе с ним через указатель и можно рассматривать как объект его бзового класса. Обратное неверно.

Будь base закрытым базовым классом класса derived, неяное преобразование derived* в base* не делалось бы. Неявное преобразование не может в этом случае быть выполнено, потому что к открытому члену класса base можно обращаться через укзатель на base, но нельзя через указатель на derived:

class base (* int m1; public: int m2; // m2 – открытый член base *);

class derived : base (* // m2 – НЕ открытый член derived *);

derived d; d.m2 = 2; // ошибка: m2 из закрытой части класса base* pb = amp;d; // ошибка: (закрытый base) pb-»m2 = 2; // ok pb = (base*) amp;d; // ok: явное преобразование pb-»m2 = 2; // ok

Помимо всего прочего, этот пример показывает, что ипользуя явное приведение к типу можно сломать правила защиты. Ясно, делать это не рекомендуется, и это приносит программиту заслуженную «награду». К несчастью , недисциплинированное использование явного преобразования может создать адские уловия для невинных жертв, эксплуатирующих программу, в котрой это делается. Но, к счастью, нет способа воспользоваться приведением для получения доступа к закрытому имени m1. Зарытый член класса

может использоваться только членами и друзьями этого класса.

7.2.5 Иерархия типов

Производный класс сам может быть базовым классом. Например:

class employee (* ... *); class secretary : employee (* ... *); class manager : employee (* ... *); class temporary : employee (* ... *); class consultant : temporary (* ... *); class director : manager (* ... *); class vice_president : manager (* ... *); class president : vice_president (* ... *);

Такое множество родственных классов принято называть ирархией классов. Поскольку можно выводить класс только из оного базового класса, такая иерархия является деревом и не может быть графом более общей структуры. Например:

class temporary (* ... *); class employee { ... *); class secretary : employee (* ... *);

// не С++: class temporary_secretary : temporary : secretary(* ... *); class consultant : temporary : employee (* ... *);

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

class temporary (* ... *); class employee (* ... *); class secretary : employee (* ... *);

// Альтернатива: class temporary_secretary : secretary (* temporary temp; ... *); class consultant : employee (* temporary temp; ... *);

Это выглядит неэлегантно и страдает как раз от тех пролем, для преодоления которых были изобретены производные классы. Например, поскольку consultant не является произвоным от temporary, consultant'а нельзя помещать с список врменных служащих (temporary employee), не написав специальный код. Однако во многих полезных программах этот метод успешно используется.

7.2.6 Конструкторы и деструкторы

Для некоторых производных классов нужны конструкторы. Если у базового класса есть конструктор, он должен вызыватся, и если для этого конструктора нужны параметры, их надо предоставить. Например:

class base (* // ... public: base(char* n, short t); ~base; *);

class derived : public base (* base m; public: derived(char* n); ~derived; *);

Параметры конструктора базового класса специфицируются в определении конструктора производного класса. В этом смысле базовый класс работает точно также, как неименованный член производного класса (см. #5.5.4). Например:

derived::derived(char* n) : (n,10), m(«member»,123) (* // ... *)

Объекты класса конструируются снизу вверх: сначала базвый, потом члены, а потом сам производный класс. Уничтожаются они в обратном порядке: сначала сам производный класс, потом члены а потом базовый.

7.2.7 Поля типа

Чтобы использовать производные классы не просто как удобную сокращенную запись в описаниях, надо разрешить следющую проблему: Если задан указатель типа base*, какому проиводному типу в действительности принадлежит указываемый обект? Есть три основных способа решения этой проблемы:

Поделиться:
Популярные книги

Здравствуй, 1985-й

Иванов Дмитрий
2. Девяностые
Фантастика:
альтернативная история
5.25
рейтинг книги
Здравствуй, 1985-й

Я сделаю это сама

Кальк Салма
1. Магический XVIII век
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Я сделаю это сама

Газлайтер. Том 18

Володин Григорий Григорьевич
18. История Телепата
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Газлайтер. Том 18

Кодекс Охотника. Книга X

Винокуров Юрий
10. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
6.25
рейтинг книги
Кодекс Охотника. Книга X

Новый Рал 9

Северный Лис
9. Рал!
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Новый Рал 9

Право на месть

Ледова Анна
3. Академия Ровельхейм
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Право на месть

Идеальный мир для Лекаря 19

Сапфир Олег
19. Лекарь
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 19

Болотник 2

Панченко Андрей Алексеевич
2. Болотник
Фантастика:
попаданцы
альтернативная история
6.25
рейтинг книги
Болотник 2

Сумеречный Стрелок 4

Карелин Сергей Витальевич
4. Сумеречный стрелок
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Сумеречный Стрелок 4

Кровь на эполетах

Дроздов Анатолий Федорович
3. Штуцер и тесак
Фантастика:
альтернативная история
7.60
рейтинг книги
Кровь на эполетах

Ржевский 6

Афанасьев Семён
6. Ржевский
Фантастика:
юмористическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Ржевский 6

Любовь Носорога

Зайцева Мария
Любовные романы:
современные любовные романы
9.11
рейтинг книги
Любовь Носорога

Черный Маг Императора 7 (CИ)

Герда Александр
7. Черный маг императора
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Черный Маг Императора 7 (CИ)

Хозяйка покинутой усадьбы

Нова Юлия
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Хозяйка покинутой усадьбы