
- •220300 - Системы автоматизированного проектирования
- •Тема 2. Технологии программирования
- •Тема 2. Технология разработки крупных приложений
- •Структуры
- •Структуры и функции
- •Массивы структур
- •Поиск в массиве структур
- •Вложенность структур
- •Рекурсия
- •Алгоритм быстрой сортировки
- •Массивы структур и бинарные файлы
- •Динамические структуры данных
- •Линейные списки
- •Очереди
- •Контрольная работа
- •Объектно-ориентированное программирование. Классы
- •Конструкторы
- •Перегруженные конструкторы
- •Определение методов класса вне класса
- •Объекты, возвращаемые функцией (методом)
- •Структуры и классы
- •Классы и память
- •Статические данные класса
- •Константные методы
- •Деструкторы
- •Массивы и классы
- •Массивы объектов
- •Строки Строковый тип или стандартный класс string
- •Тип строк AnsiString
- •Перегрузка операций
- •Перегрузка арифметических операций
- •Перегрузка операций сравнения
- •Перегрузка операции приведения типа
- •Преобразования объектов в основные типы и наоборот
- •Преобразование объектов классов в объекты других классов
- •Наследование
- •Конструкторы производного класса
- •Перегрузка функций
- •Иерархия классов
- •Общее и частное наследование. Комбинации доступа
- •Множественное наследование
- •Включение. Классы в классах
- •Виртуальные и дружественные функции
- •Абстрактные классы и чистые виртуальные функции
- •Виртуальные деструкторы
- •Виртуальные базовые классы или устранение неоднозначности при множественном наследовании
- •Дружественные функции
- •Дружественные классы
- •Указатель this
- •Многофайловые программы
- •Распознавание нажатых клавиш
Иерархия классов
До сих пор мы использовали наследование только для добавления новых возможностей к существующим классам. Теперь рассмотрим пример, где наследование применяется как часть первоначальной разработки программы.
В качестве примера рассмотрим базу данных служащих некоторой компании, в которой существует только две категории служащих: менеджеры, занятые управлением, и рабочие, занятые изготовлением товара. В базе данных хранятся имена служащих всех категорий и их идентификационные номера. В информации о менеджерах содержится ещё название их должности и заработная плата, а в информации о рабочих – квалификационный разряд.
Служащий
Имя Номер
Менеджер
Рабочий
Должность Зар.плата
Разряд
|
Программа будет состоять из базового класса, который содержит фамилии служащих и их номера и порождает два новых класса.
const int L = 80;
//---------------------------------------------------------------------------
class Sotrudnik { //базовый класс
private:
char name[L];
int number;
public:
void getdata() {
cout << "\n Vvedite FIO: "; cin.getline(name, L);
cout << " Vvedite nomer: "; cin >> number;
}
void show() const {
cout << "\n Familiya: " << name;
cout << "\n Nomer: " << number;
}
};
//---------------------------------------------------------------------------
class Manager : public Sotrudnik { //производный класс
private:
char dolgnost[L];
double oklad;
public:
void getdata() {
Sotrudnik::getdata();
cout << " Vvedite dolgnost: "; cin >> dolgnost;
cout << " Vvedite zarplatu: "; cin >> oklad;
}
void show() const {
Sotrudnik::show();
cout << "\n Dolgnost: " << dolgnost;
cout << "\n Zar. plata: " << oklad;
}
};
//---------------------------------------------------------------------------
class Worker : public Sotrudnik {
private:
int raz;
public:
void getdata() {
Sotrudnik::getdata();
cout << " Vvedite razryad: "; cin >> raz;
}
void show() const {
Sotrudnik::show();
cout << "\n Razryad: " << raz;
}
};
//---------------------------------------------------------------------------
int main() {
Manager m1;
Worker r1, r2;
cout << "\nVvod managerov: "; m1.getdata(); cin.get();
cout << "\nVvod workerov: "; r1.getdata(); cin.get(); r2.getdata();
cout << "\nVyvod managerov: "; m1.show();
cout << "\nVyvod workerov: "; r1.show(); r2.show();
getch(); return 0;
}
Обратите внимание на то, что данные базового класса объявлены с ключевым словом private. Это вызвано тем, что производным классам нет необходимости использовать эти данные напрямую. Они используют вызов методов базового класса, которые в свою очередь имеют полный доступ к данным.
В данной программе мы не определяли объекты класса Sotrudnik, а использовали его как общий базовый класс для производных классов. Здесь, ни в в базовом, ни в производных классах нет конструкторов, поэтому компилятор использует конструктор по умолчанию производного класса, вызывающий конструктор по умолчанию базового класса.
Вопрос |
Что надо добавить в эту программу, чтобы появилсь возможность инициализировать в программе объект класса Worker. int main() { … Worker r1, r2("Petrov T.I.", 333, 1); cout << "\nVvod workerov: "; r1.getdata(); cout << "\nVyvod workerov: "; r1.show(); r2.show(); getch(); return 0; } |
Ответ |
class Sotrudnik { private: char name[L]; int number; public: Sotrudnik() { strcpy(name, "\0"); number = 0; } Sotrudnik(char *fio, int n) { strcpy(name, fio); number = n; } void getdata() { cout << "\n Vvedite FIO: "; cin.getline(name, L); cout << " Vvedite nomer: "; cin >> number; } void show() const { cout << "\n Familiya: " << name; cout << "\n Nomer: " << number; } }; //--------------------------------------------------------------------------- class Manager : public Sotrudnik { … }; //--------------------------------------------------------------------------- class Worker : public Sotrudnik { private: int raz; public: Worker() : Sotrudnik() { } Worker(char *wname, int num, int r) : Sotrudnik(wname, num) { raz = r; } // или Worker(char *wname, int num, int r) : Sotrudnik(wname, num), raz(r) { } void getdata() { Sotrudnik::getdata(); cout << " Vvedite razryad: "; cin >> raz; } void show() const { Sotrudnik::show(); cout << "\n Razryad: " << raz; } };
|
Варианты написания программы
Вариант 2
При определении производных классов Manager и Worker можно было-бы использовать спецификатор private (частное наследование), например:
class Manager : private Sotrudnik {…}
class Worker : private Sotrudnik {…}
Это можно было сделать, поскольку объекты производных классов, не используют методы базового класса. В методах производных классов используется только вызов методов базового класса.
Следует понимать, когда можно использовать частное наследование, а когда – нельзя. Так, если объекту производного класса необходимо использовать непроизводный метод базового класса напрямую, то в этом случае необходимо применять общее наследование (public). Например:
…
class Manager : public Sotrudnik {
private:
char dolgnost[L];
double oklad;
public:
void getdata() {
Sotrudnik::getdata();
cout << " Vvedite dolgnost: "; cin >> dolgnost;
cout << " Vvedite zarplatu: "; cin >> oklad;
}
// void show() const {…} отсутствует этот метод
};
…
int main() {
Manager m1;
…
cout << "\nVyvod managerov: "; m1.show(); // вызовется метод базового класса
…
}
При необходимости скрыть все методы базового класса от объектов производного класса необходимо применять частное наследование.
Вариант 3
Здесь, в главной функции для ввода данных о первом рабочем мы использовали оператор r1.getdata();. Если в методе getdata() производного класса убрать вызов одноимённого метода базового класса, то тогда в главной функции вместо оператора r1.getdata(); надо было-бы написать следующее: r1.Sotrudnik::getdata(); r1.getdata();. Только в этом случае обязательно необходимо использовать общее наследование, т.е. class Worker : public Sotrudnik { … }; .