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

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

Жанры

Шрифт:

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

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

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

Я Гордый часть 2

Машуков Тимур
2. Стальные яйца
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я Гордый часть 2

Князь Мещерский

Дроздов Анатолий Федорович
3. Зауряд-врач
Фантастика:
альтернативная история
8.35
рейтинг книги
Князь Мещерский

Тринадцатый VII

NikL
7. Видящий смерть
Фантастика:
фэнтези
попаданцы
аниме
5.25
рейтинг книги
Тринадцатый VII

Наследие Маозари 9

Панежин Евгений
9. Наследие Маозари
Фантастика:
попаданцы
постапокалипсис
рпг
сказочная фантастика
6.25
рейтинг книги
Наследие Маозари 9

Страж Кодекса. Книга IV

Романов Илья Николаевич
4. КО: Страж Кодекса
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Страж Кодекса. Книга IV

Эмиссар

Листратов Валерий
8. Ушедший Род
Фантастика:
боевая фантастика
аниме
попаданцы
7.50
рейтинг книги
Эмиссар

Антология странного рассказа

Коллектив авторов
Проза:
современная проза
5.00
рейтинг книги
Антология странного рассказа

Я – Легенда

Гарцевич Евгений Александрович
1. Я - Легенда!
Фантастика:
боевая фантастика
попаданцы
рпг
фантастика: прочее
5.00
рейтинг книги
Я – Легенда

Имперец. Том 5

Романов Михаил Яковлевич
4. Имперец
Фантастика:
попаданцы
альтернативная история
аниме
6.00
рейтинг книги
Имперец. Том 5

Телохранитель Генсека. Том 4

Алмазный Петр
4. Медведев
Фантастика:
попаданцы
альтернативная история
6.00
рейтинг книги
Телохранитель Генсека. Том 4

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

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

Вечный. Книга III

Рокотов Алексей
3. Вечный
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Вечный. Книга III

Моров. Том 4

Кощеев Владимир
3. Моров
Фантастика:
фэнтези
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Моров. Том 4

Наследник

Назимов Константин Геннадьевич
3. Травник
Фантастика:
фэнтези
6.80
рейтинг книги
Наследник