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

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

Жанры

Шрифт:

Менеджер также является служащим; относящиеся к служащму employee данные хранятся в члене emp объекта manager. Для читающего это человека это, может быть, очевидно, но нет нчего выделяющего член emp для компилятора. Указатель на мнеджера (manager*) не является указателем на служащего (employee*), поэтому просто использовать один там, где требется другой, нельзя. В частности, нельзя поместить менеджера в список служащих, не написав для этого специальный код. Моно либо применить к manager* явное преобразование типа, либо поместить в список служащих адрес члена emp, но и то и другое мало элегантно и довольно неясно. Корректный подход состоит в том, чтобы установить, что менеджер является служащим с некторой добавочной информацией:

struct manager : employee (* employee* group; // ... *);

manager является производным от employee и, обратно, employee есть базовый класс для manager. Класс manager допонительно к члену group имеет члены класса employee (name, age и т.д.).

Имея определения employee и manager мы можем теперь содать список служащих, некоторые из которых являются менеджрами. Например:

void f (* manager m1, m2; employee e1, e2; employee* elist; elist = amp;m1; // поместить m1, e1, m2 и e2 в elist m1.next = amp;e1; e1.next = amp;m2; m2.next = amp;e2; e2.next = 0; *)

Поскольку менеджер является служащим, manager* может ипользоваться как employee*. Однако служащий необязательно является менеджером, поэтому использовать employee* как manager* нельзя.

7.2.2 Функции члены

Просто структуры данных вроде employee и manager на смом деле не столь интересны и часто не особенно полезны, потому рассмотрим, как добавить в них функции. Например:

class employee (* char* name; // ... public: employee* next; void print; // ... *);

class manager : public employee (* // ... public: void print; // ... *);

Надо ответить на некоторые вопросы. Как может функция член производного класса manager использовать члены его базвого класса employee? Как члены базового класса employee мгут использовать функции члены производного класса manager? Какие члены базового класса employee может использовать фунция не член на объекте типа manager? Каким образом програмист может повлиять на ответы на эти вопросы, чтобы удовлеворить требованиям приложения?

Рассмотрим:

void manager::print (* cout «„ " имя " «« name «« «\n“; // ... *)

Член производного класса может использовать открытое имя из своего базового класса так же, как это могут делать другие члены последнего, то есть без указания объекта. Предполагаеся, что на объект указывает this, поэтому (корректной) ссыкой на имя name является this-»name. Однако функция manager:: print компилироваться не будет, член производного класса не имеет никакого особого права доступа к закрытым членам его базового класса, поэтому для нее name недоступно.

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

С другой стороны, можно ведь использовать механизм friend, чтобы предоставить такой доступ или отдельным функцям, или всем функциям отдельного класса (как описывается в #5.3). Например:

class employee (* friend void manager::print; // ... *);

решило бы проблему с manager::print, и

class employee (* friend class manager; // ... *);

сделало бы доступным каждый член employee для всех фунций класса manager. В частности, это сделает name доступным для manager::print.

Другое, иногда более прозрачное решение для производного класса – использовать только открытые члены его базового класса. Например:

void manager::print (* employee::print; // печатает информацию о служащем // ... // печатает информацию о менеджере *)

Заметьте, что надо использовать ::, потому что print была переопределена в manager. Такое повторное использование имен типично. Неосторожный мог бы написать так:

void manager::print (* print; // печатает информацию о служащем // ... // печатает информацию о менеджере *)

и обнаружить, что программа после вызова manager::print неожиданно попадает в последовательность ркурсивных вызовов.

7.2.3 Видимость

Класс employee стал открытым (public) базовым классом класса manager в результате описания:

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

Это означает, что открытый член класса employee является также и открытым членом класса manager. Например:

void clear(manager* p) (* p-»next = 0; *)

будет компилироваться, так как next – открытый член и employee и manager'а. Альтернатива – можно определить закртый (private) класс, просто опустив в описании класса слово public:

class manager : employee (* // ... *);

Это означает, что открытый член класса employee является закрытым членом класса manager. То есть, функции члены класса manager могут как и раньше использовать открытые члены класса employee, но для пользователей класса manager эти члены ндоступны. В частности, при таком описании класса manager функция clear компилироваться не будет. Друзья производного класса имеют к членам базового класса такой же доступ, как и функции члены.

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

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

Глаза погребенных

Астуриас Мигель Анхель
Проза:
классическая проза
5.00
рейтинг книги
Глаза погребенных

Я уже барон

Дрейк Сириус
2. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я уже барон

Лев Толстой

Труайя Анри
Проза:
историческая проза
5.00
рейтинг книги
Лев Толстой

#Бояръ-Аниме. Газлайтер. Том 36

Володин Григорий Григорьевич
36. История Телепата
Фантастика:
боевая фантастика
аниме
фэнтези
5.00
рейтинг книги
#Бояръ-Аниме. Газлайтер. Том 36

Адмирал. Пенталогия

Светлов Дмитрий Николаевич
Адмирал
Фантастика:
фэнтези
6.29
рейтинг книги
Адмирал. Пенталогия

Цикл романов "Целитель". Компиляция. Книги 1-17

Большаков Валерий Петрович
Целитель
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Цикл романов Целитель. Компиляция. Книги 1-17

Дьюма-Ки

Кинг Стивен
Фантастика:
ужасы и мистика
8.90
рейтинг книги
Дьюма-Ки

Искусство войны

Иванов Владимир
Фантастика:
космическая фантастика
5.00
рейтинг книги
Искусство войны

Конфликт чести. Агент перемен. Лови день

Ли Шарон
Золотая библиотека фантастики
Фантастика:
боевая фантастика
6.25
рейтинг книги
Конфликт чести. Агент перемен. Лови день

Книги Бахмана

Кинг Стивен
Шедевры фантастики
Фантастика:
ужасы и мистика
мистика
5.00
рейтинг книги
Книги Бахмана

Эпоха Опустошителя. Том IV

Павлов Вел
4. Вечное Ристалище
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Эпоха Опустошителя. Том IV

Шайтан Иван 4

Тен Эдуард
4. Шайтан Иван
Фантастика:
попаданцы
альтернативная история
8.00
рейтинг книги
Шайтан Иван 4

Прозрение (сборник)

Ле Гуин Урсула Кребер
12. Вся Ле Гуин
Фантастика:
фэнтези
6.25
рейтинг книги
Прозрение (сборник)

Барону наплевать на правила

Ренгач Евгений
7. Закон сильного
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Барону наплевать на правила