C++
Шрифт:
Когда описывается производная 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*, какому проиводному типу в действительности принадлежит указываемый обект? Есть три основных способа решения этой проблемы:
Вернадский
325. Жизнь замечательных людей
Документальная литература:
биографии и мемуары
рейтинг книги
“Цесаревич” Часть I. Эскадренный броненосец. 1899-1906 гг.
Боевые корабли мира
Научно-образовательная:
история
технические науки
военная техника и вооружение
военная история
рейтинг книги
Мятежник
4. Стеллар
Фантастика:
боевая фантастика
рейтинг книги
Газлайтер. Том 16
16. История Телепата
Фантастика:
боевая фантастика
попаданцы
аниме
рейтинг книги
Старый, но крепкий 5
5. Культивация без насилия
Фантастика:
рпг
аниме
уся
фэнтези
рейтинг книги
Наномашины, сынок! Том 1
1. Чего смотришь? Иди книгу читай
Фантастика:
фэнтези
попаданцы
аниме
рейтинг книги
Изгой Проклятого Клана. Том 5
5. Изгой
Фантастика:
аниме
фэнтези
попаданцы
рейтинг книги
Геррон
Проза:
современная проза
рейтинг книги
Месть Паладина
5. Псевдоним `Испанец`
Фантастика:
фэнтези
попаданцы
аниме
рейтинг книги
Кодекс Охотника XXVIII
28. Кодекс Охотника
Фантастика:
фэнтези
боевая фантастика
попаданцы
рейтинг книги
Вечный. Книга III
3. Вечный
Фантастика:
фэнтези
попаданцы
рпг
рейтинг книги
Поворот Колеса
4. Орден Манускрипта
Фантастика:
фэнтези
рейтинг книги
Сборник "Приграничье" (1-5 части)
Приграничье
Фантастика:
боевая фантастика
рейтинг книги
Одержимый
Top Thriller
Детективы:
триллеры
маньяки
рейтинг книги