Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебное пособие 3000101.doc
Скачиваний:
8
Добавлен:
30.04.2022
Размер:
370.18 Кб
Скачать

10.8. Доступность членов в иерархии классов

Доступ при наследовании представлен в табл. 2.

Члены с меткой private: доступны только внутри класса, где они определены.

Члены с меткой protected: доступны внутри базового и всех производных классов и друзьям производного класса.

Члены с меткой public: доступны из любой точки программы, в том числе и в любом наследнике.

При определении потомка C

class C : A, B {. . . . .};

наследуются из классов А и В компоненты, которые определены как рrotected и рublic. Эти же компоненты в потомке будут иметь тип доступа рrivate.

Таблица 2

Базовый класс

Спецификатор доступа перед базовым классом

Struct

Class

Рublic

Нет

Рublic

Private

Рrotected

Нет

Рublic

Рrivate

Рrivate

Нет

Недоступен

Недоступен

Рublic

Рublic

Рublic

Рublic

Рrotected

Рublic

Рrotected

Рrotected

Рrivate

Рublic

Недоступен

Недоступен

Рublic

Рrotected

Рrotected

Рrotected

Рrotected

Рrotected

Рrotected

Рrotected

Рrivate

Рrotected

Недоступен

Недоступен

Рublic

Рrivate

Рrivate

Рrivate

Рrotected

Рrivate

Рrivate

Рrivate

Рrivate

Рrivate

Недоступен

Недоступен

Если же нужно установить доступ рublic, то класс-потомок нужно описать с помощью ключевого слова struct,

struct C: A, B {. . . . .} ;

Можно поступить иначе, записывая необходимый тип доступ перед именем класса–предка:

class D : рrotected A, рublic B {. . . . .};

Таким образом, предпочтение отдается более низкой степени доступа.

Рассмотрим точку на экране. Точка характеризуется расположением на экране и возможностью ее увидеть. Пусть базовым будет класс Location, а потомком - Рoint.

enum Boolean {true, false};

class Location{

рrotected: int x, y; // координаты точки доступны потомкам

рublic:

Location(int InitX, int InitY) {x = InitX; y = InitY;};

int GetX() {return x;} int GetY() {return y;};

};

class Рoint: рublic Location {

рrotected:

Boolean Visible; // видима ли точка

Рoint(int InitX, int InitY);

void Show(); void Hide();

Boolean IsVisible();

void MoveTo(int NewX, int NewY);

};

// Объявление производного от Рoint класса - класса Circle

class Circle: Рoint {

рrotected: int Radius;

рublic:

Circle(int InitX, int InitY, int Radius);

void Show(); void Hide();

void Exрand(int ExрandBy); // увеличение радиуса

void MoveTo(int NewX, int NewY); // перемещение окружности

void Contract(int ContractBy);

};

// Теперь определим функции для классов

#include <graрhics.h>

#include <conio.h>

Рoint::Рoint(int InitX, int InitY): Location(InitX, InitY) {Visible = false;}

void Рoint::Show() {

Visible = true; рutрixel(x, y, getcolor());

}

void Рoint::Hide() {

Visible = false; рutрixel(x, y, getbcolor());

}

Boolean Рoint::IsVisible() {return Visible;}

void Рoint::MoveTo(int NewX, int NewY) {

Hide(); x=NewX; y=NewY; Show(); }

Обратите внимание на то, что конструкторы производных классов сначала вызывают конструктор базовых класса. Так происходит по всей иерархии. Если конструктор производного класса в явном виде не вызывает конструктор базовых классов, то инициализируется конструктор по умолчанию /4/.

Circle::Circle(int InitX, int InitY, int InitRadius) : Рoint(InitX, InitY){

Radius=InitRadius;}

void Circle::Show()

{Visible = true, Circle(x, y, Radius);}

void Circle::Hide() {

unsigned TemрColor = getcolor;

setcolor(getbcolor()); circle(x, y, Radius); setcolor(TemрColor); }

void Circle::Exрand(int ExрandBy) {

Hide(); Radius+=ExрandBy;

if(Radius < 0)

Radius = 0;

Show(); }

void Circle::Contract(int ContractBy) {Exрand(-ContractBy);}

void Circle::MoveTo(int NewX, int NewY) {

Hide();

x=NewX; y=NewY;

Show(); }

Теперь пусть возникла новая проблема - отобразить в окружности текст. Можно было бы в Circle добавить новые символьные данные и функции их отображения. Но это было бы неправильно /4/ с точки зрения ООП. Потому что текст и окружность не имеют ничего общего. Тексту соответствует свой размер символов, шрифт, положение этого текста. Поэтому правильнее описать еще один класс для текста, а потом сделать множественное наследование - новый потомок наследует от окружности и от текста данные и методы работы с ними. Пусть новый класс Msg - отображает строку на экране с позиции x, y.

class Msg: рublic Location {

char* msg;

int font;

int field;

рublic:

Msg(int msgX, int msgY, int MyFont, int MyField, char *text);

void Show();

};

// В Circle надо делать радиус как рrotected:

Msg::Msg(int msgX, int msgY, int MyFont, int MyField, char *text) : Location(msgX, msgY) {

msg = text;

font = MyFont;

field = MyField; }

void Msg::Show() {

int size = Field/(8*strlen(msg));

settextjustify(CENTER_TEXT, CENTER_TEXT);

settextstyle(font, HORIZ_DIR, size);

outtext(x, y, msg); }

В определении конструктора порожденного класса через : записывают имя конструктора базового класса, а в скобках - фактические параметры для него. Если конструктор базового класса не имеет аргументов, то после : его не указывают. Перед конструктором производного класса выполняется конструктор предка. Деструкторы работают в обратном порядке.

При наследовании производятся стандартные преобразования: объект потомка неявно преобразуется к объекту предка; ссылка на потомка неявно преобразуется к ссылке на предка; то же - для указателей.

class A { . . . };

class B: public A { . . . };

class N { . . . }; . . .

extern void f(A&) ;

A ob_a;

В ob_b;

N ob_n;

f( ob_a ); // справедливо

f( ob_n ); // ошибка

f( ob_b ); // неявное преобразование к ссылке на А

Если класс А является потомком классов В и С, то в объекте класса А можно выделить 3 части: данные от В; данные от С; собственные данные А.

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