Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Кетков.doc
Скачиваний:
17
Добавлен:
27.09.2019
Размер:
2.22 Mб
Скачать

Раздел 16. Классы как средство создания больших программных комплексов

До сих пор мы знакомились с возможностями классов как средства создания и обработки новых типов данных. Наряду с этим важнейшим достижением языка C++ имеется другая, не менее важная заслуга классов, – они позволяют строить развивающиеся иерархические структуры программных комплексов. И главным механизмом здесь является наследование – возможность порождать новые классы на базе уже имеющихся с передачей порожденным классам наследства в виде данных и членов-функций родительского класса (или классов, если прямых родителей несколько). Порожденные классы имеют возможность расширять набор данных, полученных по наследству, модифицировать родительские методы и функции, создавать новые данные и новые функции их обработки. Возможность сохранять ранее созданное программное хозяйство, модифицируя его в соответствии с новыми задачами, позволяет с меньшими затратами и с большей надежностью вести разработки больших программных систем. Дополнительный выигрыш в производительности процесса разработки программного обеспечения можно получить за счет использования библиотек классов и шаблонов, активно создаваемых в настоящее время.

16.1. Базовый и производный классы

Когда говорят о классе D, порожденном из класса B, то принято называть родительский класс базовым, а вновь созданный класс – производным. Механизм наследования (inheritance) предусматривает две возможности. В первом случае, который называют простым наследованием, родительский класс один. Во втором случае родителей два или больше, и соответствующий процесс именуют термином множественное наследование. В первую очередь мы познакомимся с механизмом простого наследования.

16.1.1.Простое наследование

Итак, как формально выглядит процедура объявления производного класса D и что он получает в наследство от своего родителя – класса B ?

class D: [virtual][public|private|protected] B

{тело производного класса};

Служебное слово virtual (виртуальный) используется для предотвращения коллизий в случае сложного множественного наследования (по этому поводу см. раздел 16.2). Кроме уровней доступа public (общедоступный) и private (личный) в классах, создаваемых на базе структур (struct) и настоящих классов (class), используется еще один уровень защиты – protected (защищенный). Защищенными данными класса могут пользоваться функции и методы самого класса, производных классов и дружественные функции. При создании производного класса D может быть упомянут один из этих уровней доступа, что повлияет на изменение уровня доступа к унаследованным данным и функциям. По этому поводу в стандарте C++ существует целая таблица:

Таблица 16.1

Уровень

доступа в B

Уровень доступа

при объявлении D

Уровень доступа в D

D=struc

D=class

public

опущен

public

private

protected

опущен

public

private

private

опущен

нет доступа

нет доступа

public

public

public

public

protected

public

protected

protected

private

public

нет доступа

нет доступа

public

protected

protected

protected

protected

protected

protected

protected

private

protected

нет доступа

нет доступа

public

private

private

private

protected

private

private

private

private

private

нет доступа

нет доступа

В современной практике программирования действует общепринятое правило – родителями и потомками должны быть только настоящие классы. Поэтому о существовании третьей колонки в табл. 16.1 можно сразу забыть.

Чаще всего производный класс конструируют по следующей схеме, которая носит название открытого наследования:

class D: public B {тело производного класса};

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

Однако приведенное выше утверждение не распространяется на конструкторы и деструкторы. Они не наследуются, но к ним можно обратиться с добавлением принадлежности классу B.

В приведенном ниже примере имеет место открытое наследование производного класса D от своего родителя. Поле данных x родительского класса для потомка закрыто, но методы setb и showb сохраняют в классе D уровень доступа public. Поэтому с объектом типа D к этим методам обращаться можно:

#include <iostream.h>

#include <conio.h>

class B {

int b;

public:

void setb(int n){b=n;}

void showb(){cout<<"in B b="<<b<<endl;}

};

class D: public B {

int d;

public:

void setd(int n){d=n;}

void showd(){cout<<"in D d="<<d<<endl;}

};

void main()

{ D qq; //объявление объекта порожденного класса

qq.setb(1); //доступ к члену базового класса qq.x

qq.showb(); //доступ к члену базового класса

qq.setd(2); //доступ к члену производного класса qq.y

qq.showd(); //доступ к члену производного класса

qq.showb(); //доступ к члену базового класса

getch();

}

//=== Результат работы ===

in B b=1 //qq.x

in D d=2 //qq.y

in B b=1 //qq.x

Обратите внимание на то, что после обращения к методу setd значение поля qq.x не изменилось.

А теперь модифицируем уровень доступа при объявлении производного класса:

class D: private B {

int d;

public:

void setbd(int n,int m)

{ setb(n); //для класса D функция стала private, но она доступна

d=m; }

void showbd()

{ showb(); // для класса D функция стала private, но она доступна

cout<<"in D d="<<d<<endl;}

};

void main()

{ D qq; //объявление объекта порожденного класса

qq.setbd(1,2);

qq.showbd();

getch();

}

Результат работы программы прежний, но в доступе к методам класса B помог производный класс. В последнем примере можно заменить в объявлении класса D уровень доступа на protected – функции setb и showb получат в классе D статус protected, но они по-прежнему будут доступны, и результат работы программы будет прежним.