Задание для контрольной

advertisement
Министерство связи и массовых коммуникаций РФ
Поволжская Государственный Университет Телекоммуникаций и Информатики
МЕТОДИЧЕСКИЕ УКАЗАНИЯ
к курсовому проекту по дисциплине
«Объектно-ориентированное программирование»
для студентов специальности 230105
Одобрено Методическим Советом ПГУТИ
Автор-составитель:
НАЗАРЕНКО П.А., к.т.н.
Редактор:
КОРАБЛИН М.А., д.т.н., профессор
Рецензент:
АЛЕКСЕЕВ А.П., к.т.н., доцент
Самара 2009
Содержание
Введение........................................................................................................................ 2
Задание .......................................................................................................................... 3
Цели курсового проекта............................................................................................... 3
Рекомендации по выполнению курсового проекта ................................................... 3
Описание предметной области ................................................................................... 4
Разработка системы классов ........................................................................................ 4
Класс массива ............................................................................................................... 4
Классы обрабатываемых массивов ............................................................................. 7
Классы вывода результатов обработки ...................................................................... 9
Класс программы........................................................................................................ 10
Иерархия классов ....................................................................................................... 13
Выбор варианта .......................................................................................................... 14
Требования к оформлению пояснительной записки ............................................... 15
Защита курсового проекта ......................................................................................... 15
Рекомендуемая литература ........................................................................................ 15
Введение
Курсовой
проект
по
дисциплине
”Объектно-ориентированное
программирование” предназначен для закрепления знаний по этой дисциплине,
полученных на лекционных, лабораторных и практических занятиях. Проект
направлен на создание программного продукта, требующего при своей
разработке использования всех основных механизмов ООП.
Проект предназначен для выполнения студентами дневного и заочного
отделений.
Отдельные этапы выполнения проекта могут опережать изучение
соответствующих тем на других видах занятий. В этом случае студентам
рекомендуется пользоваться литературой, в том числе, если какие-либо вопросы
не полностью отражены в настоящем методическом руководстве.
Проект ориентирован на использование языка Си++, в отдельных случаях
допускается использование студентами других объектно-ориентированных
языков (например, Object Pascal, Java, C#, Perl, Python и т.д.), при условии, что
исполнители проекта в достаточной степени знакомы с этими языками.
2
Задание
В курсовом проекте требуется разработать программу, реализующую
обработку данных, хранящихся в массивах и содержащую объекты, которые
представляют собой массивы, выводимые на экран сообщения, элементы
интерфейса и т.п.
Программа должна позволять контролировать своё выполнение, т.е. иметь
некоторый пользовательский интерфейс.
Все компоненты программы, включая интерфейс, должны быть объектами
соответствующих классов. При разработке программы допускается использовать
RAD- и CASE-средства, например Borland C++ Builder или IBM Rational Rose.
В программе следует постараться не использовать числовые константы,
кроме как при инициализации глобальных переменных.
Можно использовать любой удобный способ (из 2-х) инициализации
объектов классов, являющихся полями других классов (обычный объект или
указатель).
Соответствующие базовые классы должны быть виртуальными.
При выполнении проекта студенты могут использовать шаблоны классов,
включая библиотеку STL.
Цели курсового проекта
1. Цель разработки – создать с использованием технологии ООП программу,
реализующую процессы в заданной предметной области, и удобную для
пользователя.
2. Учебная цель – научиться использовать основные механизмы ООП,
включая множественное наследование, полиморфизм, абстрактные классы и
перегрузку операций.
При выполнении проекта должно быть продемонстрировано умение
использовать перегрузку операций, включая operator=, operator[], виртуальные
функции, абстрактные классы, взаимодействие между объектами разных
классов.
Рекомендации по выполнению курсового проекта
Разработку программы можно вести в соответствии со спиральной моделью
жизненного цикла ПО []. В этом случае сначала создаётся прототип – программа,
обладающая минимально необходимым набором функциональных качеств и
пользовательским интерфейсом начального уровня. Набор функций расширяется
на следующих этапах разработки, одновременно может усложняться интерфейс.
При использовании технологии ООП первыми следует разрабатывать
базовые классы, как обладающие наиболее общими свойствами. Для нашего
курсового проекта это означает, что разработку можно начать с класса
обобщённого массива, продолжив её классами обрабатываемых массивов,
3
отображаемых массивов и классом всей программы в целом.
Разработка крупных программных комплексов обычно начинается с
предпроектных исследований предметной области [].
Описание предметной области
В разрабатываемой программе выполняются различные виды обработки
наборов однотипных данных, т.е. массивов. Эта обработка может заключаться в
поиске какого-либо значения, например, максимума или минимума; расчёте
среднего значения или некоторой порядковой статистики, например, медианы;
сортировке по одному из алгоритмов и т.п. В разных высокоуровневых языках
программирования массивы, векторы или списки обладают различными
свойствами, например, их размер может быть известен процедурам обработки
этих массивов по их имени или неизвестен. Применение объектноориентированного программирования позволяет задавать размер массива и
правильно его обрабатывать.
Для достижения учебной цели курсового проекта каждый вид обработки
данных в массиве выполняется с помощью отдельного класса. Кроме того,
следует предусмотреть класс, выполняющий несколько типов обработки, а также
класс, позволяющий вывести результат обработки в виде строки (для чего
необходимо описать свойства строки в виде отдельного класса).
Разработка системы классов
Класс массива
Разработку системы классов начнём с класса массива. Рассмотрим
компоненты данных этого класса. Хранимые в массиве данные могут являться
последовательностью целых чисел, действительных чисел или символов. Т.к.
размер этого массива может быть заранее не известен, то будет использоваться
динамический массив, адресуемый указателем. Таким образом, одно поле класса
массива – указатель на тип данных, определяемый вариантом задания. Ещё одно
поле – размер этого массива. С точки зрения состава полей класс массива
оказывается аналогичным классу строки TString, рассмотренному в лекционном
курсе. Аналогичным может быть и состав функций класса. Отличия у некоторых
функций от функций класса TString в том, что не будут использоваться
библиотечные функции работы со строками.
Определение класса будет размещаться в отдельном файле с именем,
например, "mas0.h", который будет включаться в другие файлы, там где это
необходимо, при помощи директивы препроцессора #include. Приведём файл с
фрагментом определения класса массива:
#ifndef MAS0
#define MAS0
class AMas
{
4
protected:
char *data;
int N;
// …
};
#endif
Набор директив
#ifndef MAS0
#define MAS0
…
#endif
предотвращает возникновение ошибок типа «повторное определение
программного объекта или типа данных» при многократном включении файла в
общий текст программы при компиляции.
Класс массива будет использоваться в качестве базового, поэтому
используется спецификатор protected. Набор конструкторов, деструктор и
функции доступа к данным в этом классе могут совпадать (полностью или
частично) с классом TString:
class AMas
{
protected:
char *data;
int N;
public:
int& GetN( ) { return N; }
AMas( ):data(NULL),N(0){}
AMas(int a):N(a) { data=new char[N]; }
int CopyData(char*,int);
// …
};
Допускается наличие других конструкторов, в зависимости от способа создания
объектов, по желанию исполнителя проекта.
Этот класс описывает свойства, общие для всех остальных массивов,
подвергаемых различным видам обработки, т.е. свойства некоторого
абстрактного массива, поэтому такой класс вполне может быть абстрактным.
Для этого он должен содержать хотя бы одну абстрактную или чистую
виртуальную функцию, например функцию обобщённой обработки массива,
кроме того, желательно, чтобы деструктор этого класса также был виртуальным:
class AMas
{
// …
virtual float Calculate( ) = 0;
virtual ~AMas( );
// …
5
};
Теория по абстрактным классам и виртуальным функциям рассмотрена в
соответствующих разделах конспекта лекций.
Полезными для этого класса могут оказаться перегруженные операции,
например, операция индексации массива [ ]:
class AMas
{
// …
public:
char& operator[](int a) { return data[a]; }
// …
};
Необходимость использования других перегруженных операций, например =
или <<, определяется студентом самостоятельно, исходя из использования
объектов соответствующих классов. Методика реализации перегрузки операций
рассмотрена в конспекте лекций.
Полное определения класса (и содержимое файла "mas0.h") оказывается
следующим:
#ifndef MAS0
#define MAS0
class AMas
{
protected:
char *data;
int N;
public:
int& GetN( ) { return N; }
char& operator[](int a) { return data[a]; }
AMas():data(NULL),N(0){}
AMas(int a):N(a) { data=new mtype[N]; }
int CopyData(char*,int);
virtual float Calculate( ) = 0;
virtual ~AMas( );
};
#endif
Определения функций класса поместим в отдельный файл с именем,
например, "mas0.cpp":
#include "mas0.h"
int AMas::CopyData(char* d,int n)
{
if(data==NULL)
return 0;
int i,n1;
if(n>=N) n1=N;
6
else n1=n;
for(i=0;i<n1;++i)
data[i]=d[i];
return i;
}
AMas::~AMas()
{
delete[] data;
}
Классы обрабатываемых массивов
Каждый класс массива, подвергаемого одной из обработок, является
производным от класса абстрактного массива и отличается от него наличием
явно существующей функции обработки, а также, возможно, наличием поля
результата обработки, например, среднего значения или найденного максимума.
Рассмотрим разработку подобного класса на примере класса подсчёта суммы
элементов массива (файл "mas1.h"):
#ifndef MAS1
#define MAS1
#include "mas0.h"
class CLsum:virtual public AMas
{
// …
protected:
char sum; // поле полученной суммы элементов массива
public:
virtual float Calculate();
float& GetSred() { return sred; }
};
#endif
Может потребоваться инициализация полей, унаследованных от класса
AMas, которая выполняется в соответствующем конструкторе:
class CLsum:virtual public AMas
{
// …
public:
CLsun( ):sum(0){} // стандартный конструктор
CLsum(int a):sum(0), AMas(a){}
};
Спецификатор virtual перед именем базового класса используется для
7
вариантов, в которых возможно множественное наследование от классов,
производных от AMas (или от какого-то другого класса, имеющегося в
программе). Если ситуация множественного наследования не возникает, то
использование спецификатора virtual не обязательно (теорию по виртуальному
наследованию см. в конспекте).
Определения функций класса поместим в отдельный файл с именем,
например, "mas1.cpp":
#include "mas1.h"
float CLsum::Calculate()
{
sum = 0;
for(int i=0;i<N;++i)
sum += data[i];
return sum;
}
Аналогичным образом разрабатываются классы, выполняющие другие
обработки массива. Все они являются производными от класса AMas, и
одновременно служат базовыми для класса, обеспечивающего несколько
обработок по разным алгоритмам. В этом случае диаграмма наследования будет
такой, как показано на рисунке 1.
AMas
CLsum
CLmax
CLSumMax
Рисунок 1. Иерархия классов абстрактного массива и различных обработок
Рассмотрим класс, для объектов которого выполняется сложная обработка:
#ifndef MAS3
#define MAS3
#include "mas1.h"
#include "mas2.h"
class CLSumMax:public CLsum, public CLmax
{
public:
CLSumMax(){}
CLSumMax(int a){ N=a; data=new char[N]; }
8
virtual float Calculate();
};
#endif
В этом классе конструктор с непустым списком аргументов самостоятельно
выполняет инициализацию полей, унаследованных от общего виртуального
базового класса (т.е. от AMas) – для предотвращения конфликтов при
использовании конструкторов своих прямых базовых классов – CLsum и
CLmax.
Сама обработка выполняется путём вызова (в общем случае, в любом
порядке) соответствующих функций требуемых базовых классов:
#include "mas3.h"
float CLSumMax::Calculate()
{
CLsum::Calculate();
CLmax::Calculate();
return sum;
}
Из других видов обработки, выбираемых по варианту задания, сортировки
массива рассматривались в курсе ”Структуры и алгоритмы обработки данных”.
Можно использовать ранее изученные процедуры сортировок, только
преобразовав их в функции соответсвующих классов. Представляют интерес
такие обработки, как вычисление медианы массива, а также его низкочастотная и
медианная фильтрация. Медиана представляет собой значение, находящееся в
центре упорядоченного набора значений. Для её нахождения массив сначала
необходимо отсортировать, например, по возрастанию, а затем найти индекс его
центрального элемента и извлечь элемент по этому индексу. Функцию,
выполняющую такую обработку, рекомендуется разработать самостоятельно.
Низкочастотная фильтрация в простейшем случае определяется выражением
S  S i  S i 1 ,
(1)
S i'1  i 1
3
где Si – текущий элемент массива, Si-1 – предыдущий элемент, Si+1 – следующий
элемент, S’i-1 – результат фильтрации, записанный в предыдущий элемент
массива. Медианная фильтрация требует сортировки данных; в случае трёх
отсчётов она определяется выражением
S i 1 , при S i  S i 1  S i 1

(2)
'
S i 1   S i , при S i 1  S i  S i 1 .
S , при S  S  S
i 1
i 1
i
 i 1
Классы вывода результатов обработки
Для вывода результата обработки в виде строки используется отдельный
класс, производный от класса строки TString (см. конспект лекций) и, в
9
зависимости от варианта, от одного из классов обработки массива.
#ifndef DSTRING
#define DSTRING
#include ”TString.h” // поключение файла с классом TString
class DString:public TString
{
protected:
float Number;
public:
void Convert(float);
// …
};
#endif
Не показанные в тексте класса конструкторы предлагается разработать
самостоятельно, по аналогии с конструкторами других классов, например,
CLsum или TString.
Преобразование из числового значения в строку выполняется с помощью
библиотечной функции sprintf:
void DString::Convert(float a)
{
sprintf(Chars,"%f",a); // Chars – поле класса TString, унаследованное классом
DString
}
Следует отметить, что для непосредственного вывода числовых значений на
экран или в файл такое преобразование не требуется, т.к. оно фактически
выполняется стандартными средствами, например cout<<…, или функцией
printf. Но преобразование может оказаться не только полезным, но даже
обязательным при объединении в одной строке текста и чисел (при этом
выполняется операция слияния строк, т.е. их конкатенация). Подобная ситуация
часто возникает при записи информации в текстовые файлы.
Класс программы
На этом этапе разработки можно создать класс программы в целом, для
проверки правильности построения функций уже созданных классов и
демонстрации их работоспособности. Полями этого класса будут объекты (или
указатели на объекты) классов CLsum и других, производных от AMas, а также
строка, возможно объект класса TString, обеспечивающая интерфейс
пользователя в виде меню допустимых команд. Функция в таком классе может
быть только одна, не считая конструкторов (одного или нескольких).
Определение класса разместим в отдельном файле, например, "prog1.h".
#ifndef PROGRAM
#define PROGRAM
10
#include "kr_ts1.h" // Все необходимые файлы с описанием классов
#include "mas0.h" // (только тех, которые используются в этом классе!!)
#include "mas1.h"
#include "mas2.h"
#include "mas3.h"
#include "kr_cl3.h"
class Program1
{
TString *menu;
AMas **bp; // Динамический массив указателей на общий базовый класс
CLmax *Max;
CLsum *Sred;
CLSumMax *comb1;
KR_CL3 *comb2;
public:
void Run();
};
#endif
Функция Run() выполняет обработку команд пользователя и производит
действия, соответствующие этим командам, например, следующим образом:
#include "prog1.h"
void Program1::Run()
{
const int NN=5;
float mas1[NN]={1,2,3,4,5};
char out[10];
menu=new TString("1-sum 2-max 3-m+s1 4-m+s2 0-vyhod");
Sred=new CLsum(NN);
Sred->CopyData(mas1,sizeof(mas1));
Max=new CLmax(NN);
Max->CopyData(mas1,sizeof(mas1));
comb1=new CLSumMax(NN);
comb1->CopyData(mas1,sizeof(mas1));
comb2=new KR_CL3(NN,out);
comb2->CopyData(mas1,sizeof(mas1));
bp=new AMas*[4]; // Динамический массив указателей
bp[0]=Sred;
bp[1]=Max;
bp[2]=comb1;
bp[3]=comb2;
char key;
do
11
{
cout<<*menu<<endl;
cin>>key;
switch(key)
{
case '1': cout<<bp[0]->Calculate()<<endl;
break;
case '2': cout<<bp[1]->Calculate()<<endl;
break;
case '3': bp[2]->Calculate();
cout<<comb1->GetSred()<<” ”<<comb1->GetMax()<<endl;
break;
case '4': bp[3]->Calculate(); comb2->Convert(comb2->GetSred());
cout<<*comb2<<endl;
comb2->Convert(comb2->GetMax());
cout<<*comb2<<endl;
break;
}
}
while(key != '0');
}
Объект класса Program1 будет создаваться в функции main(), находящейся в
главном файле проекта. Этот файл может быть очень небольшим:
#include <iostream>
using namespace std;
#include "kr_ts1.cpp"
#include "ts2.cpp"
#include "mas0.cpp"
#include "mas1.cpp"
#include "mas2.cpp"
#include "mas3.cpp"
#include "prog1.cpp"
int main()
{
Program1 prog;
prog.Run();
return 0;
}
В этом примере все файлы, включаемые директивой #include, кроме файла
"prog1.cpp", могут включаться в текст программы именно в файле "prog1.cpp".
После разработки и отладки такого ядра программы можно наращивать
состав классов и усложнять класс Program1.
12
Иерархия классов
Созданные классы находятся между собой в отношениях наследования и
агрегации, показанных в виде диаграммы иерархии классов (рисунок 2).
Линиями с треугольными стрелками показаны отношения наследования, с
ромбовидными стрелками – вхождение объектов (или указателей) в класс
Program1 (т.е. агрегация).
TString
AMas
CLsum
CLmax
DString
CLSumMax
Program1
CL3
Рисунок 2. Полная диаграмма иерархии классов (для одного варианта)
В конкретных случаях диаграммы иерархии классов могут отличаться от
приведённой, в зависимости от варианта задания.
Дополнительные рекомендации
Виртуальные функции должны во всех классах иметь один и тот же прототип,
поэтому у всех таких функций Calculate в рассмотренном примере используется
тип возвращаемого значения float (стр. 5), требуемый только для функции
расчёта среднего значения. Если по варианту задания выполняются другие виды
обработок, и результатом ни одной из них не является действительное число, то
можно выбрать другой тип возвращаемого значения, например, совпадающий с
типом хранимых в массиве данных. Если результатом каждой из обработок
является не число, а новое состояние массива, например, после сортировки или
фильтрации, то можно выбрать тип возвращаемого значения void (во всех
перечисленных случаях допускается игнорировать тип результата, задаваемый
по варианту (табл. 2).
Если одна из виртуальных функций выполняет, например, сортировку
массива и должна возвращать число (независимо от типа, float, double, int или
char) (т.к. другая функция, например, ищет максимум и должна вернуть
результат), то в качестве результата первой функции можно использовать любое
разумное значение, например, число элементов в массиве, значение нулевого
(или последнего) элемента массива и т.п. При необходимости такое «фиктивное»
возвращённое значение в вызвавшей функции можно не использовать.
13
При выполнении низкочастотной и медианной фильтраций по выражениям
(1) и (2) с целью экономии памяти результат фильтрации можно занести в
исходный обрабатываемый массив. Если этот результат заносится в текущий
элемент, то такая фильтрация называется рекуррентной. Если результат
заносится в один из ужЕ просмотренных элементов, значение которого больше
не используется, например, предыдущий, то получается нерекуррентная (т.е.
обычная фильтрация). В обоих случаях цикл просмотра элементов массива
должен начинаться не с 0, а с 1, и заканчиваться на значении не N-1, а N-2 (т.к.
элементы с индексами на 1 меньше и на 1 больше также участвуют в
вычислениях:
for (int i = 1; i <= N – 2; ++i )
// или for (int i = 1; i < N – 1; ++i )
data [i – 1] = (data [i – 1] + data [i] + data [i + 1] ) / 3 ;
Во всех случаях возможно также возникновение «краевых» эффектов
(начальный и конечный элементы массива или не подвергаются обработке, или
получают значения, не соответствующие выражениям (1) или (2)). Эти эффекты
в курсовом проекте можно не учитывать.
Выбор варианта
Вариант задания курсового проекта выбирается по 2-м последним цифрам
номера зачётной книжки, которые обозначим через nnnАВ. Предпоследняя
цифра А определяет тип массива данных (поле data в классе AMas), чётная или
нечётная цифра А также определяет направление сортировки для тех
вариантов, в которых, она применяется (таблица 1).
Таблица 1.
А Тип данных в массиве
0 char
1 unsigned char
2 int
3 unsigned int
4 long
5 unsigned long
6 short
7 unsigned short
8 float
9 double
Направление сортировки
по возрастанию
по убыванию
по возрастанию
по убыванию
по возрастанию
по убыванию
по возрастанию
по убыванию
по возрастанию
по убыванию
Последняя цифра В определяет выполняемые обработки и тип результата
виртуальных функций Calculate (таблица 2)
14
Таблица 2.
В
Выполняемые обработки
0
1
2
3
4
5
6
7
8
9
Расчёт среднего значения + поиск максимума
Сортировка пузырьковая + расчёт медианы
Поиск минимума + низкочастотная фильтрация
Извлечение центрального элемента + сортировка вставками
Сортировка отбором + медианная фильтрация
Расчёт среднего значения + расчёт медианы
Сортировка Шелла + поиск максимума
Сортировка отбором + поиск минимума
Расчёт медианы + извлечение центрального элемента
Сортировка пузырьковая + сортировка Шелла
Тип
результата
float
double
float
double
float
double
float
double
float
double
Требования к оформлению пояснительной записки
Пояснительная записка к курсовому проекту должна содержать:
1. полное описание варианта задания,
2. диаграмму иерархии классов,
3. полный исходный текст программы.
Пояснительная записка должна быть оформлена в соответствии со
стандартами на проектную документацию, иметь оглавление и бланк рецензии.
Страницы должны быть пронумерованы.
Защита курсового проекта
На защите курсового проекта от студента требуется:
1. обосновать выбор классов в иерархии,
2. обосновать выбор компонентов классов,
3. объяснить фрагменты текста программы по выбору преподавателя,
4. продемонстрировать работу программы.
Рекомендуемая литература
1. Подбельский В.В. Язык Си++. – М.: Финансы и статистика, 1995.
2. Фридман А.Л. Основы объектно-ориентированной разработки программных
систем. – М.: Финансы и статистика, 2000.
3. Фридман А.Л. Основы объектно-ориентированного программирования на
языке Си++. Учебный курс. – М.: Радио и связь, 1999.
4. Иванова Г. и др. Объектно-ориентированное программирование. – М.: МГТУ
им. Баумана, 2001.
5. Глушаков С.В., Коваль А.В., Смирнов С.В. Язык программирования C++.
Учебный курс. – Харьков: Фолио; М.: ООО «Издательство АСТ», 2001.
15
Related documents
Download