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

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

Жанры

Шрифт:

Менеджер также является служащим; относящиеся к служащму 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 компилироваться не будет. Друзья производного класса имеют к членам базового класса такой же доступ, как и функции члены.

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

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

Здравствуй, 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
рейтинг книги
Хозяйка покинутой усадьбы