- •3. Ұсынылатын әдебиеттер тізімі / список рекомендуемой литературы
- •1.Обзор стилей программирования
- •1.1. Процедурное программирование
- •1.2. Структурное программирование
- •1.3. Функциональное программирование
- •1.4. Логическое программирование
- •1.5. Объектно-ориентированное программирование
- •2. Основные принципы объектно-ориентированного программирования
- •3.1. Объявление классов и объектов
- •3.2. Конструкторы и деструкторы
- •3.3. Область видимости компонент класса
- •3.4. Определение компонентных функций класса
- •3.5. Статические компоненты классов
- •3.6. Дружественные функции
- •3.7. Перегрузка операций
- •4. Наследование классов
- •4.1. Повторное использование классов: наследование и агрегирование
- •4.3. Множественное наследование
- •4.4. Виртуальные классы
- •4.5. Виртуальные функции. Полиморфизм
- •4.6. Абстрактные классы
- •Методические указания по выполнению лабораторных работ
- •1. Краткие теоретические сведения
- •1.1. Структура программы
- •1.2. Константы и переменные
- •1.3. Операции
- •1.4. Выражения
- •1.5. Ввод и вывод
- •1.5.1. Ввод и вывод в стандартном Си
- •2. Постановка задачи
- •3. Варианты
- •4. Методические указания
- •5. Содержание отчета
- •Краткие теоретические сведения
- •Составные операторы
- •Операторы выбора
- •Операторы циклов
- •Операторы перехода
- •2. Постановка задачи
- •3. Варианты
- •3. Содержание отчета
- •4. Методические указания
- •1. Краткие теоретические сведения
- •2. Постановка задачи
- •3. Варианты
- •4. Методические указания
- •5. Содержание отчета
- •Краткие теоретические сведения
- •1.1. Определение массива
- •1.2. Инициализация массива
- •1.3. Указатели
- •1.4. Указатели и массивы
- •2. Варианты заданий
- •3. Методические указания
- •4. Содержание отчета
- •Краткие теоретические сведения
- •1.1. Функции
- •1.2. Массивы и строки как параметры функций
- •2. Постановка задачи
- •3. Варианты
- •4. Содержание отчета
- •Задания на лабораторные работы Классы. Протокол класса. Конструкторы и деструкторы
- •Краткие теоретические сведения Виртуальные функции и полиморфизм План
- •Задания для самостоятельной работы
- •Лабораторная работа №8 "Производные классы: множественное наследование"
- •Задания на лабораторные работы по Объектно-ориентированному программированию, множественное наследование
- •Экзаменационные вопросы
4.6. Абстрактные классы
При проектировании иерархических систем классов программисты обычно стремятся выделить некоторые обобщающие свойства некоторой группы описываемых сущностей в базовый класс (в предыдущих главах такими классами были Subject, Figure, Shape). Зачастую созданные по такому принципу классы носят абстрактный смысл, не описывая какой-то реально существующий объект, а лишь являясь некоторой основой, на которой строятся действительно необходимые классы. Это приводит к некоторому несоответствию спроектированной системы классов предметной области: оказывается, что программист может определить в программе объекты, реально к предметной области не имеющие никакого отношения. Для того, чтобы предотвратить возможность использования объектов таких классов в программе, их объявляют абстрактными. Абстрактным называется класс, в котором определена хотя бы одна чистая виртуальная функция. Чистая виртуальная функция определяется следующим образом:
virtual тип имя_функции( список_формальных_параметров )=0;
Чистая виртуальная функция не имеет реализации, ее нельзя вы- звать в программе, она служит лишь как основа для дальнейшего поли- морфного переопределения в производном классе. Соответственно, аб- страктный класс не может иметь объектов, так как в нем не определены операции над объектами (или, по крайней мере, хотя бы одна операция, реализуемая чистой виртуальной функцией).
Рассмотрим пример.
//Листинг 32. Использование абстрактных классов
#include <stdio.h>
#include <iostream.h>
#include <string.h>
#include <conio.h>
class File //абстрактный класс
{ protected:
char **str; //адрес буфера для временного хранения информации из файла
char Name[30]; //имя файла
int n; //количество строк в буфере
virtual int ReadFile()=0; //чистая виртуальная функция чтения информации из файла в буфер
public: File(char*,int);
~File();
void display(); //метод, отображающий содержимое буфера на экране
};
File::File(char * FileName,int k) //конструктор
{ strcpy(Name,FileName);
n=k;
str=new char*[n]; //выделяем память под буфер
for(int i=0;i<n;i++)
str[i]=new char[80];
}
File::~File() //деструктор
{for(int i=0;i<n;i++)
delete []str[i]; //освобождаем память
delete [] str;
}
void File::display()
{ clrscr();
int k=ReadFile(); //считываем информацию из файла в буфер
for(int i=0;i<k;i++)
cout<<str[i]; // построчно выводим содержимое буфера на экран
getch();
}
struct info //тип информации, хранящейся в файле
{char name[20]; char numb[10]; float value;
};
class InfoFile:public File //класс «файл с базой данных»
{ int ReadFile(); //переопределяем функцию чтения информации из файла
public:
InfoFile(char* st,int k):File(st,k) {} //конструктор вызывает конструктор базового класса
void WriteFile(int ); //метод записи информации в файл
};
int InfoFile::ReadFile()
{ FILE *fp; int i=0; info x;
if((fp=fopen(Name,"r"))!=NULL) //открываем файл
{ while(!feof(fp)) //пока не конец файла
{ fread(&x,sizeof(info),1,fp); //считываем очередную запись из файла
sprintf(str[i],”Запись N %d %s %s %f\n",i+1,x.name,x.numb,x.value);
//заносим очередную запись в буфер файла
i++;
}
fclose(fp);
return i-1; //функция возвращает количество считанных из файла записей
}
return 0;}
void InfoFile::WriteFile(int k)
{ info x; FILE *fp;
if((fp=fopen(Name,"w+"))!=NULL)
{ for(int i=0;i<k;i++)
{cout<<”Введите "<<i+1<<" -ю запись";
cin>>x.name>>x.numb>>x.value; //вводим с клавиатуры очередную запись
fwrite(&x,sizeof(info),1,fp); //записываем ее в файл
}
fclose(fp);
}}
class HelpFile:public File //класс «файл с помощью»
{ int ReadFile(); //переопределяем функцию чтения информации из файла
public:
HelpFile():File("help.dat",25){} //имя файла и его размер фиксированы
};
int HelpFile::ReadFile()
{ int i=0; FILE *fp;
if((fp=fopen(Name,"r"))!=NULL)
{ while(!feof(fp))
{fgets(str[i],80,fp); //считываем содержимое файла в буфер
i++;
} fclose(fp); return i-1;
}
return 0;}
main()
{ HelpFile hp; //объект класса «файл с помощью»
hp.display(); //выводим содержимое файла на экран
InfoFile If("info",40); //создаем объект класса «файл с информацией» If.WriteFile(3); //записываем в файл 3 записи
If.display(); //выводим содержимое файла на экран
}
Программа,
приведенная в листинге 32, работает с
файлами двух типов –информационным
файлом (класс InfoFile),
предназначенным для хранения простейшей
базы данных – нескольких структур типа
info,
а также файлом помощи
(класс
HelpFile),
который хранит текстовую информацию,
предположительно – справку о самой
программе. Общаясущность двух этих
типов файлов, выражающаяся в имени файла
Name,
буфере str для
временного хранения информации из
файла, размере используемого файлом
буфера n,
а также метода display
вывода
считанной из файла информации на экран,
выделена в родительский класс (класс
File).
Метод display класса File считывает информацию из файла методом ReadFile в буфер и построчно выводит ее на экран. Однако, метод ReadFile в самом классе File не может быть полноценно определен, поскольку этот класс в терминах предметной области является абстрактной основой для двух других классов (InfoFile и HelpFile) и для него не известен, например, тип хранящейся в файле информации. Метод ReadFile определен в классах InfoFile и HelpFile , причем в первом данный метод считывает из файла информацию в виде экземпляров структуры info, преобразует ее в текстовую форму и записывает в буфер, а во втором - информация непосредственно считывается в виде текстовых строк, которые записываются в буфер str. Таким образом, метод ReadFile не надо определять в классе File по логике представления предметной области, однако обязательно необходимо определить по правилам синтаксиса языка С++ (так как метод display использует этот метод). При этом необходимо обеспечить полиморфное поведение метода ReadFile для того, чтобы при вызове метода display объектом класса InfoFile в теле метода display была вызвана реализация метода ReadFile для соответствующего класса (аналогичная ситуация рассматривалась в листинге 31). Поэтому метод ReadFile объявлен в классе File как чистая виртуальная функция:
virtual int ReadFile()=0;
Таким образом, класс File является абстрактным классом, для которого запрещено создание объектов, то есть ошибкой будет такое объявление:
File MyFile(“file.txt”,50);
Класс File может быть только основой для дальнейшего наследо- вания другими классами. Подводя итог, можно сказать, что абстрактные классы используются для спецификации интерфейсов операций (мето- ды, реализующие эти операции впоследствии определяются в производ- ных классах абстрактного класса). Абстрактные классы удобны на фазе анализа требований к системе, так как они позволяют выявить аналогию в различных, на первый взгляд, операциях, определенных в анализируемой системе.
