
Штерн В. - Основы C++. Методы программной инженерии - 2003
.pdf560 Часть III • riporpoiviiviiipoBaHiie с агрвтроваиивт и иасАВАОванивт
Объект производного класса может обращаться только к компонентам private и protected, унаследованным из базового класса. Для доступа к собственным за крытым компонентам, унаследованным из базового класса, следует использовать функции доступа базового класса. На первый взгляд это неразумно. Объект про изводного класса не имеет доступа к собственным компонентам! Ничего подобного нам раньше не встречалось.
С другой стороны, производный класс является клиентом базового класса. Базовый класс может иметь элементы (особенно данные), архитектура которых со временем меняется. Если сделать эти элементы доступными для производных классов, то их потребуется и модифицировать. При доступе через отличные от private функции производные классы защищены от влияния изменений в базо вых классах. По этой же причине элементы данных объявляются закрытыми, а функции-члены — общедоступными.
Листинг 13.5. Доступ к компонентам классов Base и Derived в производном объекте
для класса Derived и для клиента при наследовании в режиме public
#include <iostream> using namespace std;
class Base { |
// доступ только изBase |
||
|
private: int privB; |
||
|
protected: int protB; |
// доступ из Base и Derived |
|
|
public: void publB() |
// доступ из Base, Derived, Client |
|
|
{ privB = 0; protB = 0; } } ; |
// OKдля доступа к собственным данным |
|
class Derived : public Base { |
// режим наследования public |
||
|
private: int privD; |
|
|
|
protected: int protD; |
|
|
|
public: void publD() |
// OKдля доступа к собственным данным |
|
|
{ |
privD = 0; protD = 0; |
|
// |
protB = 0; |
// ОКдля доступа к унаследованным компонентам |
|
privB = 0; |
// нет доступа к унаследованным компонентам |
||
|
|
} } ; |
|
class Client { |
// конструктор класса Client |
||
public: ClientO |
|||
{ |
Derived d; |
// объект производного класса |
|
|
d.publDO; |
// ОКдля доступа к сервисам public |
|
|
d.publBO; |
// ОКдля доступа к сервисам public класса Base |
|
|
/ / |
d.privD = d. protD = 0; |
// нет доступа к отличным отpublic сервисам |
|
/ / |
d.privB=d.protB=0; |
// нет доступа к отличным отpublic сервисам |
|
|
}; |
|
int |
mainO |
// создает объект, выполняет программу |
|
{ |
Client c; |
||
|
return 0; |
|
|
|
} |
|
|
В листинге 13.5 показана связь между объектом производного класса и его собственными компонентами. Здесь класс Derived является производным от
класса Base в режиме public. Класс Base, как и Derived, имеет компоненты private, public и protected. Производный класс вметоде publD() может обра
щаться ксобственным компонентам privD и protD. Кроме того, он может отно ситься к унаследованным компонентам public и protected класса Base — protB
и publB(). РАежду тем попытка класса Derived обратиться кзакрытым компонен там privB, унаследованным из класса Base, была бы синтаксической ошибкой.
Глава 13 • Подобные классы и их интерпретация |
561 |
хотя в объекте Derived распределяется память для этого компонента. Класс Client создает объект класса Derived в своем конструкторе и обращается к обндедоступным сервисам, определенным в классе Derived (publD()) и в классе Base (publD()). Он не может обращаться к отличным от public компонентам классов Base
иDerived. Поскольку здесь демонстрируются права доступа к средствам Base
иDerived, программе не нужно выдавать никакого результата. Она генерирует только сообщения компилятора об ошибках.
Наследование public — наиболее естественный режим наследования, так как при этом сохраняется связь типа "является видом" между классами. При создании производного класса в таком режиме объекты предлагают клиенту все общедо ступные средства, присутствующие в базовом объекте, и добавляют дополнитель ные. Возможности дальнейшего наследования также не ограничиваются.
Внимание при создании производного класса в режиме public унаследованные компоненты базового класса сохраняют в объектах производного класса свой статус доступа (private, protected или public). Все общедоступные (public) сервисы, определенные в производном классе и унаследованные из базового, доступны клиенту. Это самый естественный режим наследования.
Листинг 13.6 показывает более крупный пример использования наследования. Для доступа к компонентам х и у базовый класс Point предлагает два сервиса public — set() и get(). Производный класс VisiblePoint добавляет к этим средствам элемент данных visible и функции-члены show(), hide() и retrieve(). Метод showO устанавливает элемент данных visible в 1. В результате точка будет отображаться графической программой. Наследование происходит в режиме public. Вместо числовых значений для отображаемых и скрытых точек лучше было бы использовать перечисление, но для компактности примера выбраны именно числа.
Листинг 13.6. Доступ к базовым компонентам в производном объекте при наследовании в режиме public
#inclucle <iostream> using namespace std;
class Point |
{ |
|
|
|
|
|
/ / |
базовый класс |
|
||
int |
X, y; |
|
|
|
|
|
|
/ / |
закрытые данные базового класса |
||
public: |
|
|
|
|
|
|
|
|
|
|
|
void |
set |
(int x i , |
int |
yi) |
|
|
|
|
|||
{ X = x i ; у = y i ; } |
|
|
|
|
|
|
|||||
void |
get |
(int &xp, |
int |
|
&yp) const |
/ / |
общедоступные методы базового класса |
||||
{ |
xp = x; |
yp = y; |
} |
} |
; |
|
|
|
|
||
class VisiblePoint |
: public Point { |
/ / |
двоеточие |
перед |
public |
||||||
int |
visible; |
|
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
/ / |
двоеточие |
после |
public |
|
void showO |
|
|
|
|
|
|
|
|
|
||
{ visible |
= 1; |
} |
|
|
|
|
|
|
|
||
void |
hideO |
|
|
|
|
|
|
|
|
|
|
{ visible |
= 0; |
} |
|
|
|
|
|
|
|
||
void |
retrieve(int |
&xp, |
int &УР, int &vp) const; |
|
|
||||||
{ |
xp = x; |
yp = y; |
|
|
|
// синтаксическая ошибка: закомментируйте ее! |
|||||
get(xp,yp); |
|
|
|
|
// доступ к методу базового класса |
||||||
vp = visible; |
} |
} |
; |
|
// производные закрытые данные: ОК |
Глава 13 • Подобные классы и их интерпретация |
563 I |
Наследование в режиме protected
|
|
Такое |
наследование представляет собой механизм, ограничивающий доступ |
||
|
к сервисам базового класса. Компоненты public и protected, наследуемые из |
||||
|
базового класса, становятся компонентами protected в объекте производного |
||||
|
класса. |
|
|
|
|
|
|
Сервисы базового класса доступны для дальнейшего наследования и исполь |
|||
|
зуются в методах производного класса. Однако клиент не может обраш,аться |
||||
|
через объект производного класса к сервисам public базового класса, поскольку |
||||
|
|
Объект |
|
теперь они являются защищенными (protected). |
|
|
|
|
На рис. 13.8 показаны изменения в отношении |
||
|
производного класса |
|
|||
Базовая |
|
private |
|
|
режима наследования protected. То, что было |
|
|
|
public в базовом классе, становится protected |
||
|
protected |
|
|||
часть объекта |
|
|
в производном классе. Пунктирная линия по |
||
производного класса |
|
protected |
|
||
|
|
казывает, что доступ для клиента к этой части |
|||
|
|
|
|||
Производная |
|
private |
|
|
объекта производного класса запрещен. |
часть обг>екта |
|
protected |
|
Листинг 13.7 демонстрирует абстрактный |
|
производного класса |
|
public |
|
Клиент |
пример из листинга 13.5, когда режим насле |
Рис. 13.8. Доступ |
к компонентам |
базового |
дования public заменяется на protected. Этот |
||
пример иллюстрирует соотношения ме>кду объ |
|||||
класса |
и производного класса |
ектом производного класса и его собственными |
|||
из объекта |
производного |
класса |
компонентами, а также между данным объек |
||
и из клиента при |
наследовании |
||||
в режиме |
protected |
|
том и клиентом. |
Листинг 13.7. Доступ к компонентам Base и Derived объекта Derived для класса Derived и клиента при режиме наследования protected
#include <iostream> using namespace std;
class Base { |
// доступ только изBase |
|
|||
private: int privB; |
|
||||
protected: int protB; |
// доступ изBase и Derived |
|
|||
public: void publB() |
// доступ изBase, Derived, Client |
|
|||
{ privB = 0; protB = 0; } } ; |
// OKдля доступа к собственным данным |
|
|||
class Derived : protected Base { |
// режим наследования protected |
|
|||
private: int privD; |
|
|
|
|
|
protected: int protD; |
|
|
|
|
|
public: void publD() |
// OKдля доступа |
к собственным данным |
|
||
{ |
privD = 0; protD = 0; |
|
|||
// |
protB = 0; |
// ОК для доступа |
к унаследованным компонентам |
||
privB = 0; |
// нет доступа |
к унаследованным компонентам |
|
||
|
} } ; |
|
|
|
|
class Client { |
// код клиента |
|
|
|
|
public: |
|
|
|
|
|
ClientO |
// объекты производного и базового классов |
|
|||
{ |
Derived d; Base b; |
|
|||
// |
d.publDO; |
// часть public производного класса: ОК |
|
||
d.publBO; |
// нет доступа к сервисам public класса Base |
Derived |
|||
// |
d.privD = d. protD = 0; |
// нет доступа |
к отличным отpublic сервисам |
||
// |
d.privB=d.protB=0: |
// нет доступа |
к отличным отpublic сервисам |
Base |
|
|
b.publBO; } |
// объект Base: часть public, ОК |
|
||
|
} |
|
|
|
|
I 564 |
|
Часть III • Програмттрошаиме с агрегирование1У1 и наследованием |
|
i nt |
mainO |
|
|
{ |
Client |
с; |
/ / создает объект, выполнят программу |
|
return |
0; |
|
|
} |
|
|
Вспомним вызов функции-члена publB() класса Base с производным объектом в качестве получателя сообщения — d.publBO (в предыдущем примере из лис тинга 13.5). В листинге 13.7 это синтаксическая ошибка. Заметим, что доступ к компонентам Base отвергается только тогда, когда он осуществляется через объект класса Derived. В конце применяемого по умолчанию конструктора ClientO вызываемая функция-член publB() использует в качестве целевого объекта объект b класса Base. Компонент public доступен клиентам этого класса. Данный сервис недоступен клиентам класса Derived.
Листинг 13.8. Доступ к базовым компонентам в производном объекте при наследовании в режиме protected
ttinclude |
<iostream> |
|
|
|||
using |
namespace std; |
|
|
|||
class |
Point |
{ |
// базовый класс |
|||
protected: |
|
// закрытые данные базового класса |
||||
|
int |
X, |
y; |
|
||
public: |
|
|
|
|
||
|
void set |
(int x i , int yi) |
|
|
||
|
|
{ X = xi; у = yi; } |
|
// общедоступные методы базового класса |
||
|
void get (int &xp, int &yp) const |
|
||||
|
{ xp = x; yp = y; } } ; |
|
|
|||
class VisiblePoint : protected Point { |
// наследование protected |
|||||
|
int visible; |
|
|
|||
public: |
|
|
|
|
||
|
void showO |
|
|
|||
|
{ visible = 1; } |
|
|
|||
|
void hideO |
|
|
|||
|
{ visible = 0; } |
|
|
|||
|
void retrieve(int &xp, int &УР, int &vp) const; |
|||||
// |
{ xp = x; yp = y; |
|
// доступ к данным protected: OK |
|||
|
get(xp,yp); |
|
// не будем усложнять |
|||
|
|
vp = visible; } |
|
|
||
|
void initialize(int xp, int yp, int vp) |
// новый сервис public |
||||
|
{ X = xp; У = yp; |
|
// доступ к данным protected базового класса |
|||
|
|
visible = vp; } } ; |
|
// доступ к данным private производного класса |
||
int mainO |
|
|
|
|
||
{ |
VisiblePoint a, b; intx.-y.z; |
|
// определение двух производных методов |
|||
// |
b.initialize(20,40,1); |
|
// инициализация производного объекта |
|||
a.set(0,0); b.set(20,40); |
|
// теперь это синтаксическая ошибка |
||||
// |
a.hideO; b.showO; |
|
// вызов метода public производного класса: ОК |
|||
a.get(x,y); |
|
// это синтаксическая ошибка |
||||
|
b.retrieve(x,y,z); |
|
// вызов метода public производного класса |
cout « |
" Координаты точки: x=" « x |
« " у=" « У « endl; |
cout « |
" Видимость точки: visible=" |
« Z « endl; |
return 0; |
|
|
} |
|
|
Глава 13 • Подобные классы и их интерпретация |
565 |
В листинге 13.8 показан пример из листинга 13.6, где режим наследования public заменен на protected. Базовый класс Point предлагает те же сервисы set() и get(), но клиент производного класса VisiblePoint не может их использо вать — это защищенные объекты VisiblePoint. Попытка сделать это в конструк торе Client О дает синтаксическую ошибку. Чтобы разрешить проблему, в класс VisiblePoint добавлен новый сервис initializeO, обращающийся к унаследо ванным элементам данных х и у вместо get() и set(). Обратите внимание, что теперь производный класс без проблем обращается к базовому классу, поскольку данные базового класса объявлены как protected. В функции-члене retrieveO производного класса закомментирован вызов базовой функции get().
Если закомментировать две строки с синтаксическими ошибками, программа будет работать и давать тот же результат, что и программа из листинга 13.6 (см. рис. 13.7).
Остается надеяться, что наследование protected понравилось вам больше, чем public. Наследование public — это способ добавления сервисов в дополнение к предлагаемым базовым классам или замены некоторых сервисов (без изменения имени) на что-то более полезное для клиента производного класса. Во всех при мерах наследования public между производными и базовыми объектами со блюдается отношение "является видом". Для клиента объект SavingsAccount "является видом" объекта Account со средствами начисления процентов. Объект VisiblePoint (видимая точка) представляет собой вид объекта Point (точка) с до бавленным свойством "отображаемая/скрытая".
При наследовании protected все происходит иначе. Это техника для быстрого создания класса, использующего отличные от public сервисы базового класса (элементы данных х и у в листинге 13.8). Однако в этомхлучае клиентам не предоставляются сервисы public базового класса (методы set() и get() в лис тинге 13.8). Им предлагается другой набор сервисов (метод initializeO в лис тинге 13.8), которые, по тем или иным причинам, больше подходят для клиента.
В листинге 13.8 объект VisiblePoint не является объектом Point. Объекты Point предлагают клиентам методы set () и get(), а объект VisiblePoint — нет.
Еще один популярный пример использования наследования protected — со здание стекового класса, предоставляющего клиентам доступ к конечному элемен ту стека. Он является производным от класса массива, который предоставляет доступ к любому компоненту. Используя наследование, разработчик может запре тить клиентам работать с массивом. Стек предлагает методы push() и рор() для доступа к вершине стека.
Вначале данной главы уже отмечалось важное различие между наследованием
икомпозицией классов. Производные классы предоставляют своим клиентам все сервисы public базового класса. Составной класс не дает клиентам сервисов свои компоненты, если эти сервисы не поддерживают методы составного класса. (В приведенных примерах класс Rectangle предусматривал сервис move().)
Если нужно закрыть клиенту доступ к некоторым из существующих сервисов, не используйте наследование. Вместо него применяйте композицию классов.
В листинге 13.9 показан пример из листинга 13.8, но класс VisiblePoint те перь является компонентом данных класса Point, а не наследником Point в режи ме protected. Результат примера тот же, что и на рис. 13.7.
Сервисы set() и get() базового класса Point скрываются от клиента из-за композиции классов. Элементы данных Point оказываются скрытыми внутри объекта VisiblePoint и недоступны клиенту. В результате клиент не сможет де лать с объектом VisiblePoint то, что он мог делать с объектом Point — переме щать по экрану безотносительно к видимости. Вместо этого класс VisiblePoint предоставляет клиенту собственный интерфейс — функции-члены initializeO и retrieveO, требующие, чтобы клиент работал с видимыми объектами.
Все это применимо к любой ситуации, когда нужно спроектировать для обслу живания клиентов новый класс. Более того, у вас есть класс, который желательно
566 Часть III • Программирование с агрегированием и наследованием
использовать в данном проекте. Если клиенту нужны все сервисы существующего класса плюс еще что-то, лучше применять наследование из этого класса в режиме public. Для унаследованных и добавленных сервисов клиент будет использовать объекты производного класса. Если сервисы существующего класса будет исполь зовать не клиент, а новый класс, не стоит применять наследование, даже в режиме protected. Лучше прибегнуть к композиции классов (см. главу 12).
Л и с т и нг 13.9. Использование композиции классов вместо наследования
#include <iostream> using namespace std;
class Point |
{ |
|
|
|
|
|
|
// компонентный класс |
||
private: |
|
|
|
|
|
|
|
|
// закрытые данные |
|
int |
X. |
y; |
|
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
|
|
|
void |
set |
(int x i , |
int |
yi) |
|
|
||||
{ X = x i ; у = y i ; } |
|
|
|
// общедоступные методы базового класса |
||||||
void |
get (int &xp, int &yp) const |
|
||||||||
{ |
xp |
= x; |
yp = y; |
} |
} |
: |
|
|
||
class VisiblePoint |
{ |
|
|
|
|
// нет наследования, композиция |
||||
Point pt; |
|
|
|
|
|
|
|
// закрытый компонент |
||
int |
visible; |
|
|
|
|
|
|
|
||
public: |
|
|
|
|
|
|
|
|
// новый сервис для клиента |
|
void showO |
|
|
|
|
|
|
||||
{ visible = 1; } |
|
|
|
|
// новый сервис для клиента |
|||||
void |
hideO |
|
|
|
|
|
|
|
||
{ |
visible |
= 0; |
} |
|
|
|
|
|
||
void |
retrieve(int |
&xp, |
int &yp, int &vp) const; |
// замена |
||||||
{ |
pt.get(xp,yp); |
|
|
|
|
// сервисы скрыты от клиента |
||||
vp = visible; |
} |
|
|
|
|
|
||||
void |
i n i t i a l i z e ( i n t |
xp, |
int yp, int vp) |
// замена |
||||||
{ |
pt.set(xp,yp); |
|
|
|
|
// сервисы скрыты от клиента |
||||
visible |
= vp; |
} |
} |
; |
|
|
// аналогично скрытым частным данным |
|||
int mainO |
|
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
// определение составного объекта |
VisiblePoint |
b; int |
x, |
y, z; |
|
||||||
b .initialize(20,40,1); |
|
|
|
// сервис составного класса |
||||||
b. ShowO; |
|
|
|
|
|
|
|
// сервис составного класса |
||
b. retrieve(x,y,z); |
|
|
|
у=" « у « |
// сервис составного класса |
|||||
cout « |
" Координаты точки: x=" « x « |
endl; |
||||||||
cout « |
" Видимость точки: visible=" « |
z « endl; |
|
return 0;
}
Наследование в режиме protected может быть полезным в ситуации, когда разрабатывается класс (или семейство классов) для обслуживания клиентов. Советуем строить этот класс поэтапно.
Например, клиенту требуется класс D1 и нужно получить производный класс D1 из D, который, в свою очередь, является производным от класса В. Применяя на следование в режиме protected для создания класса D, производного от В, и клас са D1, производного от D, можно построить класс D1, использующий все сервисы
Глава 13 • Подобные КАОССЫ И ИХ интерпретация |
567 |
|
public и protected класса D. Эти сервисы включают в себя |
сервисы |
public |
и protected класса В. Клиент D1 не будет использовать сервисы |
public классов В |
иD, которые скрываются от клиента благодаря режиму наследования protected. Другими словами, наследование protected предоставляет способ для ограниче
ния доступа клиентов к сервисам public базового класса. При этом не ограничива ется доступ к этим сервисам из производного класса и продолжается дальнейшее наследование.
Внимание наследование в режиме protected скрывает от клиента сервисы базового класса, используемые объектом производного класса. Тем самым искажается отношение "является видом". Если оно не важно, используйте вместо наследования protected композицию классов.
Если же чувствуете, что следует применить наследование, лучше использовать режим public. (Хотя это предвзятая точка зрения.)
Наследование в режиме private
Наследование в режиме private представляет собой технику ограничения до ступа к базовым сервисам не только для клиентов производных классов, но и для производных классов от данных производных классов.
Когда базовый класс используется как private, все его компоненты public и protected становятся в объекте производного класса компонентами private. Они недоступны для клиентов производных классов, а также для методов классов, производных от производного класса. Их могут использовать методы производного класса.
В этом состоит важное отличие использования базового класса как private от других режимов наследования. При наследовании protected и public правила доступа транзитивны. Если производный класс использует базовый класс для дальнейшего наследования (protected или public), то производный класс имеет те же права доступа к компонентам базового класса, что и класс, непосредственно полученный из базового. Если же наследование происходит в режиме private и производный класс используется для дальнейшего наследования, то его потомки не будут иметь доступа ни к каким компонентам базового класса. К компонентам protected и public базового класса может обращаться только класс, непосредст венно производный от базового (дочерний). Тем самым разработчик производного класса предотвращает использование сервисов базового класса в дальнейшем наследовании.
Как и в случае наследования protected, |
|
|
private |
|
общедоступный интерфейс (public) базового |
Часть Base |
|
|
|
|
private |
|
||
класса (данные и методы) не является частью |
|
|
||
объекта Derived |
|
|
||
интерфейса производного класса. Для клиента |
|
|
private |
V\\\ |
все это закрыто (private). |
Часть Derived |
|
private |
|
Данные связи показаны на рис. 13.9. При |
|
protected |
\ |
|
наследовании в режиме private объект класса, |
объекта Derived |
|
public |
Client code |
производного от производного класса, не имеет |
Часть Derived |
|
private |
^ |
доступа к своим собственным компонентам, |
|
|
||
объекта, |
|
protected |
|
|
унаследованным от базового класса. |
|
|
||
производного |
I |
|
||
Листинг 13.10 снова показывает небольшой |
от объекта Derived |
public |
|
|
абстрактный пример. На этот раз используется |
|
Объект класса, |
||
наследование private. Что же касается прав |
|
производного от класса Derived, |
||
доступа производного объекта к своей базовой |
|
который является производным |
||
части, то они здесь такие же, что и в преды |
|
от Base в режиме private |
||
Рис. 13.9. Доступ к базовым |
|
|||
дущем примере (с наследованием в режиме |
компонентам |
|||
protected). |
из объекта |
производного класса |
||
|
при |
наследовании |
private |
568 |
Часть III • Програ^/1мирование с агрегированием и наследованием |
|||
Листинг 13.10. Доступ к компонентам Base в иерархии наследования, |
|
|
||
|
когда класс Derived наследует из класса Base в режиме |
private |
|
|
#include <iostream> |
|
|
|
|
using namespace std; |
|
|
|
|
class Base { |
// доступ только из Base |
|
|
|
|
private: int privB; |
|
|
|
|
protected: int protB; |
// доступ из Base и Derived |
|
|
|
public: void publB() |
// доступ из Base и Derived |
|
|
|
{ privB = 0; protB = 0;} } |
// OKдля доступа к собственным данным |
|
|
class Derived : private Base { |
// режим наследования private |
|
||
|
private: int privD; |
|
|
|
|
protected: int protD; |
|
|
|
|
public: void publD() |
// OKдля доступа к собственным данным |
|
|
|
{ privD = 0; protD = 0; |
|
||
// |
protB = 0; |
// ОКдля доступа к унаследованным компонентам |
||
privB = 0; |
// нет доступа к унаследованным компонентам |
|||
class Derivedl : public Derived { |
// класс, производный отDerived |
|
||
public: void publDDO |
// нет доступа к "базовым" данным private |
|||
{ |
// privD = 0 |
|||
protD = 0; |
// OKдля доступа к "базовым" данным protected |
|||
publDO; |
// OKдля доступа к "базовым" данным public |
|||
// |
protB = 0; |
// нет доступа клюбой части |
"закрытой |
базы" |
|
publBO; |
// нет доступа клюбой части |
"закрытой |
базы" |
} } ; |
|
|
|
|
class Client { |
|
|
|
|
public: |
|
|
|
|
ClientO |
// объекты производного и базового классов |
|||
{ |
Derived d; Base b; |
|||
d.publDO; |
// часть public класса Derived: OK |
|
||
// |
d.publBO; |
// часть public Base класса Derived: не OK |
||
// |
d.privD = d. protD = |
// отличная отpublic часть Derived: не OK |
||
// |
d.privB=d.protB=0; |
// отличная отpublic часть Base в Derived: не ОК |
||
b.publBO; } |
// часть public Base объекта Base: OK |
|
||
|
} |
|
|
|
int mainO |
// создает объект, выполняет программу |
|
||
{ |
Client c; |
|
||
return 0; |
|
|
|
|
} |
|
|
|
Чтобы программу можно было скомпилировать, здесь закомментированы не
сколько нарушаюш,их правила строк. Производный класс может обращаться ко всем отличным от private компонентам базового класса. Это не зависит от ре жима наследования. Аналогично, класс Derivedl может обращаться ковсем не
закрытым компонентам собственного "базового" класса (Derived). Это также не связано с режимом наследования. Между тем в режиме private класс Derivedl не может обращаться к компонентам базового класса Base.Что касается клиента,
для него наследование private аналогично наследованию protected. Все компо ненты базового класса в производном объекте недоступны для клиента.
Наследование private допускает написание новых серверов с помощью уже
реализованных элементов. Однако в этом случае подтипы неимеют отношений. Если в режиме private изкласса Array создается объект Stack, последний не
является объектом Array и непредоставляет клиентам Stack или классам, на
следующим из Stack, сервисы Array.