АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Наследование. Понятие наследования. Конструкторы порожденного класса. Иерархия классов. Абстрактный базовый класс

Читайте также:
  1. I. Понятие и значение охраны труда
  2. I. Понятие общества.
  3. II. ОСНОВНОЕ ПОНЯТИЕ ИНФОРМАТИКИ – ИНФОРМАЦИЯ
  4. II. Понятие социального действования
  5. IV класс.
  6. Unknown — базовый интерфейс COM
  7. А. Понятие жилищного права
  8. А. Понятие и общая характеристика рентных договоров
  9. А. Понятие и признаки подряда
  10. А. Понятие и элементы договора возмездного оказания услуг
  11. А. Понятие и элементы комиссии
  12. А. Понятие и элементы простого товарищества

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

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

Конструкторы производного класса

Это потенциальная проблема в программе COUNTEN. Что будет, если мы захотим инициализировать значением объект класса CountDn? Сможем ли мы воспользоваться конструктором класса Counter с одним аргументом? Ответ будет отрицательным. Как мы видели в программе COUNTEN, компилятор будет использовать конструктор базового класса без аргументов. Мы должны написать новый конструктор для производного класса.

// counten2.cpp

// конструкторы в производных классах

#include <iostream>

using namespace std;

///////////////////////////////////////////////////////////

class Counter

{

protected: // заметьте, что тут не следует использовать private

unsigned int count; // счетчик

public:

Counter (): count () // конструктор без параметров

{ }

Counter (int c): count (c) // конструктор с одним параметром

{ }

unsigned int get_count () const // получение значения

{ return count; }

Counter operator++ () // оператор увеличения

{ return Counter (++count); }

};

///////////////////////////////////////////////////////////

class CountDn: public Counter

{

public:

CountDn (): Counter () // конструктор без параметров

{ }

CountDn (int c): Counter (c)// конструктор с одним параметром

{ }

CountDn operator-- () // оператор уменьшения

{ return CountDn (--count); }

};

///////////////////////////////////////////////////////////

int main ()

{

CountDn c1; // переменные класса CountDn

CountDn c2 (100);

 

cout << "\nc1 = " << c1.get_count (); // выводим значения на экран

cout << "\nc2 = " << c2.get_count ();

 

++c1; ++c1; ++c1; // увеличиваем c1

cout << "\nc1 = " << c1.get_count (); // показываем результат

 

--c2; --c2; // уменьшаем c2

cout << "c2 = " << c2.get_count (); // показываем результат

 

CountDn c3 = --c2; // создаем переменную c3 на основе c2

cout << "\nc3 = " << c3.get_count (); // показываем значение

 

cout << endl;

 

return 0;

}

Программа использует два новых конструктора класса CountDn. Это конструктор без аргументов:

CountDn (): Counter ()
{ }

В этом конструкторе использована новая для нас возможность: имя функции, следующее за двоеточием. Она используется конструктором класса CountDn для вызова конструктора Counter() базового класса. Когда мы запишем в функции main()

CountDn c1;

компилятор создаст объект класса CountDn и вызовет конструктор класса CountDn для его инициализации. Конструктор в свою очередь вызовет конструктор класса Counter, который выполнит нужные действия. Конструктор CountDn() может выполнять и свои операции, кроме вызова другого конструктора, но в нашем случае это не требуется, поэтому пространство между скобками пусто.

Вызов конструктора в списке инициализации может быть лишним, но это имеет смысл. Мы хотим инициализировать поле, не важно, принадлежит оно базовому или производному классу, и перед выполнением любого оператора программы сначала будут выполнены операции конструктора.
В строке:

CountDn c2 (100);

функции main() используется конструктор класса CountDn с одним аргументом. Этот конструктор вызывает соответствующий конструктор с одним аргументом из базового класса:

CountDn (int c): Counter (с) // параметр с передается в конструктор класса Counter
{ }

Такая конструкция означает, что аргумент с будет передан от конструктора CountDn() в Counter(), где будет использован для инициализации объекта. В функции main() после инициализации объектов c1 и c2 мы увеличиваем один из них и уменьшаем другой, а затем выводим результат. Конструктор с одним аргументом также используется в выражениях присваивания:


CountDn c3 = --c2;

 

Иерархия классов

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

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

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

Пример нашей программы начинается с описания базового класса employee. Этот класс содержит фамилии служащих и их номера. Он порождает три новых класса: manager, scientist и laborer. Классы manager и scientist содержат добавочную информацию об этих категориях служащих.

 

// employ.cpp

// employ.cpp

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

using namespace std;

const int LEN = 80; // максимальная длина имени

///////////////////////////////////////////////////////////

class employee // некий сотрудник

{

private:

char name[ LEN ]; // имя сотрудника

unsigned long number; // номер сотрудника

public:

void getdata ()

{

cout << "\n Введите фамилию: "; cin >> name;

cout << " Введите номер: "; cin >> number;

}

void putdata () const

{

cout << "\n Фамилия: " << name;

cout << "\n Номер: " << number;

}

};

///////////////////////////////////////////////////////////

class manager: public employee // менеджер

{

private:

char title[ LEN ]; // должность, например вице-президент

double dues; // сумма взносов в гольф-клуб

public:

void getdata ()

{

employee::getdata ();

cout << " Введите должность: "; cin >> title;

cout << " Введите сумму взносов в гольф-клуб: "; cin >> dues;

}

void putdata () const

{

employee::putdata ();

cout << "\n Должность: " << title;

cout << "\n Сумма взносов в гольф-клуб: " << dues;

}

};

///////////////////////////////////////////////////////////

class scientist: public employee // ученый

{

private:

int pubs; // количество публикаций

public:

void getdata ()

{

employee::getdata ();

cout << " Введите количество публикаций: "; cin >> pubs;

}

void putdata () const

{

employee::putdata ();

cout << "\n Количество публикаций: " << pubs;

}

};

///////////////////////////////////////////////////////////

class laborer: public employee // рабочий

{

};

///////////////////////////////////////////////////////////

int main ()

{

manager m1, m2;

scientist s1;

laborer l1;

 

// введем информацию о нескольких сотрудниках

cout << endl;

cout << "\nВвод информации о первом менеджере";

m1.getdata ();

 

cout << "\nВвод информации о втором менеджере";

m2.getdata ();

 

cout << "\nВвод информации о первом ученом";

s1.getdata ();

 

cout << "\nВвод информации о первом рабочем";

l1.getdata ();

 

// выведем полученную информацию на экран

cout << "\nИнформация о первом менеджере";

m1.putdata ();

 

cout << "\nИнформация о втором менеджере";

m2.putdata ();

 

cout << "\nИнформация о первом ученом";

s1.putdata ();

 

cout << "\nИнформация о первом рабочем";

l1.putdata ();

 

cout << endl;

return 0;

}

В функции main() этой программы объявлены четыре объекта различных классов: два объекта класса manager, объект класса scientist и объект класса laborer. (Конечно, объектов могло быть много больше, но при этом вывод про- граммы стал бы довольно объемным.) Они вызывают метод getdata() для получения информации о каждом из служащих и метод putdata(), обеспечивающий вывод этой информации.

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

 

Абстрактный базовый класс

Заметим, что мы не определяли объекты класса employee. Мы использовали его как общий класс, единственной целью которого было стать базовым для производных классов.

Класс laborer выполняет те же функции, что и класс employee, так как не имеет никаких отличий от него. Может показаться, что класс laborer в данном случае лишний, но, создав его, мы подчеркнули, что все классы имеют один источник — класс employee. Кроме того, если мы захотим в будущем модифицировать класс Laborer, то нам не потребуется делать изменения в классе employee.

Классы, использующиеся только как базовые для производных, например как employee в программе EMPLOY, иногда ошибочно называют абстрактными классами, подразумевая, что у этого класса нет объектов. Однако термин абстрактный имеет более точное определение.

 


1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 |

Поиск по сайту:



Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.012 сек.)