Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование_на_С++_Ч2_ООП.doc
Скачиваний:
54
Добавлен:
22.02.2015
Размер:
633.34 Кб
Скачать

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

Простым называется наследование, при котором производный класс имеет одного родителя. Для различных методов класса существуют разные правила наследования – например, конструкторы и операция присваивания в производном классе не наследуются, а деструкторы наследуются.

Пример. Описание класса daemon, производного от класса monstr:

enum color {red, green, blue};

// monstr

class monstr {

//

int health, ammo;

color skin;

char * name;

public:

//

monstr (int he=100, int am=10);

monstr (color sk);

monstr (char *nam);

monstr (monstr &M);

//

~ monstr ( ) {delete [ ] name;}

//

monstr & operator ++ ( ) {

++ health; return *this;

}

monstr operator ++ (int) {

monstr M (*this);

health ++; return M;

}

operator int ( )

return health;

}

bool operator > (monstr &M) {

if (health > M.get_heath ( )) return true;

return false;

}

const monstr & operator = (monsr &M) {

if (&M == this) return *this;

if (name) delete [ ] name;

if (M.name) {

namt = new char [strlen(M.name)+1];

strcpy (name, M.name); }

else name = 0;

health =M.health; ammj=M.ammo; skin =M.skin;

return *this;

}

//

int get_health ( ) const {return health;}

int get_ammo ( ) const { return ammo;}

//

void change_health (int he) {healt=he;}

//

void draw (int x, int y, int scale, int position);

//

monstr :: monstr (int he, int am):

health (he), ammo (am), skin (red), name (0) { }

monstr :: monstr (monstr &M) {

if (M.name) {

name = new char [strlen(M.name)+1];

strcpy (name, M.name;}

else name = 0;

health =M.health; ammo=M.ammo; skin = M.skin;

}

monstr :: monstr (color sk) {

switch (sk) {

case red: health =100; ammo=10; skin = red;

name=0; break;

case green: health =100; ammo=20, skin=green;

name=0; break;

case blue: health =100; ammo=40; skin=blue;

name=0; break;

}

}

monstr :: monstr (char * nam) {

name = new char [strlen(nam)+1];

strcpy(name, nam);

health =100; ammo =10; skin = red;

}

void monstr :: draw (int x, int y, int scale, int position)

{/**/}

//

class daemon : public monstr {

int brain;

public:

//

daemon (int br=10) {brain = br;}

daemon (color sk) : monstr (sk) {brain = 10;}

daemon (char *nam) : monstr (nam) {brain = 10;}

daemon (daemon &M) : monstr (M) {brain = M.brain;}

//

const daemon &operator = (daemon &M) {

if (&M == this) return *this;

brain = M.brain;

monstr :: operator =(M);

return *this;

}

//

void think ( );

//

void draw (int x, int y, int scale, int position);

}

//

void daemon :: think ( ) {/* */}

void daemon :: draw (int x, int y, int scale, int position) {/* */}

!!! В классе daemon введено поле brain и метод think, определены собственные конструкторы и операция присваивания, а также переопределен метод draw. Все поля класса monstr, операции (кроме присваивания) и методы get_health, get_ammo и change_health наследуются в классе daemon, а деструктор формируется по умолчанию.

Правила наследования методов

Конструкторы не наследуются, поэтому производный класс должен иметь собственные конструкторы. Порядок вызова конструкторов определяется следующими правилами:

– если в конструкторе производного класса явный вызов конструктора базового класса отсутствует, автоматически вызывается конструктор базового класса по умолчанию (т. е. тот, который можно вызвать по умолчанию; пример – первый из конструкторов класса daemon);

– для иерархии, состоящей из нескольких уровней, конструкторы базовых классов вызываются, начиная с самого верхнего уровня. После этого выполняются конструкторы тех элементов класса, которые являются объектами, в порядке их объявления в классе, а затем исполняется конструктор класса;

– в случае нескольких базовых классов их конструкторы вызываются в порядке объявления.

Не наследуется операция присваивания, поэтому ее следует также явно определить в производном классе.

Для деструкторов существуют следующие правила наследования:

– деструкторы не наследуются, и если программист не описал в производном классе деструктор, он формируется по умолчанию и вызывает деструкторы всех базовых классов;

– в отличие от конструкторов при написании деструкторов производного класса в нем не требуется явно вызывать деструкторы базовых классов;

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

Поля, унаследованные из класса monstr, недоступны функциям производного класса, поскольку они определены в базовом классе как private. Если функциям, определенным в daemon, требуется работать с этими полями, можно либо описать их в базовом классе как protected, либо обращаться к ним с помощью функций из monstr, либо явно переопределить их в daemon.

В классе daemon описан метод draw, переопределяющий метод с тем же именем в классе monstr. Доступ к переопределяющему методу базового класса для производного класса выполняется через имя, уточненное с помощью операции доступа к области видимости (::).

Задание

Образуйте производный класс от созданного вами класса, который в дополнение к родительским методам может вычислять тригонометрические функции, степенную функцию (степень – вещественное число), экспоненциальную функцию и десятичный логарифм.