Лабораторная работа №6-7

Тема: Организация иерархии одиночного наследования. Абстрактные классы (аппарат визуальных функций). Композиция. Контейнерные и производные классы. Открытые и закрытые производные классы. Применение правил доступа в иерархии классов. Возможность повторного использования кода.

Цель:

- познакомиться с абстрактными классами;

- научиться создавать программы на С++ с использованием контейнерных и производных классов;

- уметь использовать открытые и закрытые производные классы.

Краткая теория.

Абстрактные классы - это классы, которые содержат хотя бы одну чистую виртуальную функцию. Абстрактные классы используются исключительно как базовые для других классов. Нельзя создать объекты абстрактных классов.

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

class base {

public:

virtual print() =0;

virtual get() =0;

}

Естественно, что определять тела этих функций не требуется.

Одна из особенностей порожденного класса - видимость унаследованных членов. Для определения доступности членов основного класса порожденному классу используются ключевые слова public, protected и private. Рассмотрим пример:

class student {

protected:

int id;

char name[30];

public:

sudent(int i,char *nm);

void print();

};

class grad_student : public student {

protected:

char thesis[30];

public:

grad_student(int i,char *nm, char *t);

void print();

};

В этом примере grad_student - порожденный класс, а student - базовый класс. Использование ключевого слова public в заголовке описания порожденного класса означает, что protected и public члены класса student должны быть унаследованы как protected и public члены grad-student соответственно. Члены private недоступны. Общее наследование также означает, что полученный класс grad-student - подтип класса student. Следовательно, студент окончивший институт - студент.

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

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

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

class man {

char name[20]; // Другие элементы класса

char *address;

dat dat1; // Дата рождения

dat dat2; // Дата поступления на работу

public:

void newadr(); // Элемент-функция

man(char*); // Конструктор

}

//----- Функция "Изменить адрес проживания" ----------------

void man:: newadr() {

int n;

char s[80]; // Строка нового адреса

if (address != NULL)

delete address; // Освободить память

printf("Введите новый адрес:");

gets(s);

address = new char[strlen(s)+1];// Занять новую память

strcpy(address,s); // Заполнить поле адреса

}

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

Практические задания:

Наследование. Иерархия и контейнерные классы.

1. Разработать программу, решающую задачу о 8 ферзях. На шахматной доске расставить 8 ферзей таким образом, чтобы ни один не бил другого.

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

3. Создать базовый класс - очередь с двумя концами. Элементы могут удаляться и добавляться с любой стороны. Создать производный класс - стек и очередь (обычная).

Виртуальные функции

1. Разработать абстрактный класс - форма с интерфейсом площадь, периметр и распечатать. Создать производные от формы - круг, прямоугольник, треугольник, реализовав эти интерфейсы.

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