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

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

Жанры

Шрифт:

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

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

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

Последний реанорец. Том XII – Часть I

Павлов Вел
11. Высшая Речь
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Последний реанорец. Том XII – Часть I

Локки 6. Потомок бога

Решетов Евгений Валерьевич
6. Локки
Фантастика:
аниме
фэнтези
5.00
рейтинг книги
Локки 6. Потомок бога

When the Mirror Cracks

OcSola
Драматургия:
драма
5.00
рейтинг книги
When the Mirror Cracks

Я до сих пор не царь. Книга XXVII

Дрейк Сириус
27. Дорогой барон!
Фантастика:
юмористическое фэнтези
аниме
попаданцы
5.00
рейтинг книги
Я до сих пор не царь. Книга XXVII

Тайник

Джордж Элизабет
12. Инспектор Линли
Детективы:
криминальные детективы
7.78
рейтинг книги
Тайник

Народ, да!

Коллектив авторов
Старинная литература:
мифы. легенды. эпос
5.00
рейтинг книги
Народ, да!

Политолог

Проханов Александр Андреевич
Проза:
современная проза
5.20
рейтинг книги
Политолог

Дэниел Мартин

Фаулз Джон Роберт
Проза:
современная проза
7.91
рейтинг книги
Дэниел Мартин

Крым 1944. Весна освобождения

Ткаченко Сергей Николаевич
Военные тайны XX века
Документальная литература:
биографии и мемуары
5.00
рейтинг книги
Крым 1944. Весна освобождения

День драконов

Земляной Андрей Борисович
3. Странник
Фантастика:
боевая фантастика
9.14
рейтинг книги
День драконов

Наша навсегда

Зайцева Мария
2. Наша
Любовные романы:
современные любовные романы
эро литература
5.00
рейтинг книги
Наша навсегда

Я еще не бог. Книга XXXV

Дрейк Сириус
35. Дорогой барон!
Фантастика:
аниме
попаданцы
5.00
рейтинг книги
Я еще не бог. Книга XXXV

Горе от богатства

Пембертон Маргарет
Любовные романы:
исторические любовные романы
7.83
рейтинг книги
Горе от богатства

Колдуны и капуста

Уланов Андрей Андреевич
2. Однажды на Диком западе
Фантастика:
фэнтези
7.54
рейтинг книги
Колдуны и капуста