Объектно-ориентированное программирование Автобусы и маршруты
Содержание
Содержание <_
1. Введение <_
2. Постановка задачи <_
3. Структура выходных и входных данных <_
4. Описание основных классов <_
5. Листинг программы <_
6. Результат работы программы <_
7. Заключение <_
8. Литератур <_
1. Введение
Язык программирования служит двум связанным между собой целям: он дает программисту аппарат для задания действий, которые должны быть выполнены, и формирует концепции, которыми пользуется программист, размышляя о том, что делать. Первой цели идеально отвечает язык, который настолько "близок к машине", что всеми основными машинными аспектами можно легко и просто оперировать достаточно очевидным для программиста образом. С таким мыслом первоначально задумывался C. Второй цели идеально отвечает язык, который настолько "близок к решаемой задаче", чтобы концепции ее решения можно было выражать прямо и коротко. С таким мыслом предварительно задумывались средства, добавленные к C для создания C++.
Связь между языком, на котором мы думаем/программируем, и задачами и решениями, которые мы можем представлять в своем воображении, очень близка. По этой причине ограничивать свойства языка только целями исключения ошибок программиста в лучшем случае опасно. Язык предоставляет программисту набор концептуальных инструментов; если они не отвечают задаче, то их просто игнорируют. Например, серьезные ограничения концепции казателя заставляют программиста применять вектора и целую арифметику, чтобы реализовать структуры, указатели и т.п. Хорошее проектирование и отсутствие ошибок не может гарантироваться чисто за счет языковых средств. Система типов должна быть особенно полезна в нетривиальных задачах. Действительно, концепция классов в C++ показала себя мощным концептуальным средством.
2. Постановка задачи
Написать информационную систему по чёту автобусных рейсов. Информационная система должна позволять:
Вести учет автотранспорта (преимущественно автобусного). В свою очередь следует:
учитывать время отправления каждого автобуса;
учитывать типы автобусов;
привязывать автотранспорт (автобусы) к рейсам;
Вести учет рейсов. В свою очередь следует:
учитывать пути, составляющие рейс;
Вести учет остановочных пунктов
Система должна обеспечить выполнение этих возможностей путем реализации алгоритмов даления, редактирования и добавления новой информации.
При этом при далении следует обеспечить целостность данных и выводить предупреждение пользователю в тех случаях, когда удаление информации невозможно в результате наличия связей с другими сущностями.
При добавлении необходимо разработать механизм, реализующий проверку на никальность, который в случаях, когда необходимо соблюдать никальность, будет предупреждать пользователя о недопустимости таких действий, также будет препятствовать добавлению такой информации. Также необходимо обеспечить проверку на пустоту и ограничивать действия пользователя в тех случаях, когда он пытается ввести пустые значения.
При редактировании следует аналогичным образом проверять редактируемые значения проверять на никальность.
Для реализации поставленной задачи использовать Visual Studio C<++ версии не ниже 6.0. В частности применить библиотеку Microsoft Foundation Classes (MFC), представляющую интерфейс ODBC для доступа к базам данных и другие возможности.
3. Структура выходных и входных данных
Программа использует СУБД Access. В ней будет разработана основная база (bus.mdb). Разрабатываемая программа будет взаимодействовать с базой путем интерфейса MFC< ODBC, что позволяет размещать данные как непосредственно на локальном компьютере, так и на любой машине в сети, предоставляющий открытый доступ к такого рода ресурсам.
База данных содержит в себе необходимое и достаточное количество нормализованных сущностей - таблиц:
Bus - таблица, размещающая информацию об автобусах. Содержит три поля: первое - это никальный идентификатор автобуса, однозначно определяющий его во всем множестве других автобусов, второе - тип автобуса, третье - никальный идентификатор рейса.
|
|
Race - таблица, размещающая информацию о рейсах. Имеет два поля:а первое - это никальный идентификатор рейса, однозначно определяющий его во всем множестве других рейсов, второе - описание рейса.
|
Race Название тип race_ID счетчик path_ID поле memo
Station - таблица, размещающая информацию об остановочных пунктах автобусов. Имеет два поля - это никальный идентификатор остановочного пункта, однозначно определяющий его во всем множестве других остановочных пунктах, и поле с его названием. Название тип station_ID длинное целое name длинное целое
Time - таблица, размещающая информацию о временах отправлений автобусов[1]<.
Автобусы, привязанные к одному рейсу, в течении определенного периода могут неоднократно отправляться в рейс в разные часы, что и отражается структурой данной таблицы. Таблица состоит из 3 полей: первое - это никальный идентификатор времени, однозначно определяющий его во всем множестве других времен отправлений, второе поле - это идентификатор автобуса, свеянный с таблицей Bus (поскольку таблица Bus связанна с Time связью один ко многим,
в Time может присутствовать несколько идентификаторов одного автобуса), третье поле - время отправления. Название тип time_ID счетчик bus_ID длинное целое time длинное целое
Type - таблица, размещающая информацию о типах автобусов
(классов). Имеет два поля - это никальный идентификатор типа,
однозначно определяющий его во всем множестве других типов, и поле с названием типа. Название тип busType_ID счетчик name поле Схема данных представлена в таблице 1.
Она отражает сущности, также связи и их типы. Таблица 1 - схема данных 4. Описание основных классов На рисунке 1 изображена диаграмма классов. Она отражает все классы проекта. Практически все классы являются пользовательскими. Они переопределены от встроенных классов путем однократного и множественного наследования. Класс CMyDBVariant представляет собой объект, способный хранить различные типы данных. Он незаменим для работы с базой данный. Его прародителем стал класс CDBVariant.
Поскольку возможностей базового класса оказалось недостаточно, пришлось его переопределить, вводя дополнительные переменные m<_cstring для передачи строк типа Cstring и m<_time для передачи времени типа CTime. CMyDBRecordset - новый класс от CDBRecordset. Более гибок,
нежели стандартный класс. Позволяет легко, без внедрения дополнительных переопределений, на месте, быстро создать представление сущности. В него добавлены:
Count - член класса,
хранящий количество записей (это сделано в силу того, что метод GetCount не возвращает реального количества), DefineRealCount - метод, определяющий Count.
Также в этот класс входит fieldnames и fieldValues,
позволяющий не передавать непосредственно переменные в метод DoFieldExchange держать их прямо в классе в качестве его членов, что значительно прощает код и способ обращения к полям представления. Полное описание классов находиться в листинге программы. Рисунок 1 - Диаграмма классов 5. Листинг программы CAboutForm.cpp #include "stdafx.h" #include "../main.h" #include "CAboutForm.h" CAboutForm::CAboutForm(CWnd*
pParent):CDialog(CAboutForm::IDD,pParent){
/{{AFX_DATA_INIT(CAboutForm)
/}}AFX_DATA_INIT <} oid CAboutForm::DoDataExchange(CDataExchange*
pDX){ CDialog::DoDataExchange(pDX);
/{{AFX_DATA_MAP(CAboutForm)
/}}AFX_DATA_MAP <} BEGIN_MESSAGE_MAP(CAboutForm, CDialog)
/{{AFX_MSG_MAP(CAboutForm)
/}}AFX_MSG_MAP END_MESSAGE_MAP() CAboutForm.h #if
!defined(AFX_CABOUTFORM_H__09D6634D_16A6_44E9_849C_AD1B2E71646D__INCLUDED_) #define
AFX_CABOUTFORM_H__09D6634D_16A6_44E9_849C_AD1B2E71646D__INCLUDED_ #if _MSC_VER > 1 #pragma once #endif // _MSC_VER > 1 // CAboutForm.h : header file // ///////////////////////////////////////////////////////////////////////////// // CAboutForm dialog class CAboutForm : public CDialog { // Construction public: CAboutForm(CWnd*
pParent = NULL); / standard
constructor // Dialog Data /{{AFX_DATA(CAboutForm) /
NOTE: the ClassWizard will add data members here /}}AFX_DATA // Overrides /
ClassWizard generated virtual function overrides /{{AFX_VIRTUAL(CAboutForm)
/}}AFX_VIRTUAL // Implementation protected: /
Generated message map functions /{{AFX_MSG(CAboutForm) /
NOTE: the ClassWizard will add member functions here /}}AFX_MSG DECLARE_MESSAGE_MAP() }; //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional
declarations immediately before the previous line. #endif //
!defined(AFX_CABOUTFORM_H__09D6634D_16A6_44E9_849C_AD1B2E71646D__INCLUDED_) CBusForm.cpp #include "stdafx.h" #include "../main.h" #include "CBusForm.h" #include "CTypeForm.h" #include "../ExLibrary/CMyRecordset.h" CString
IsEmpty_CEdit(CEdit* ctrl); CBusForm::CBusForm(CWnd*
pParent):CDialog(CBusForm::IDD, pParent){
/{{AFX_DATA_INIT(CBusForm)
/}}AFX_DATA_INIT <} oid CBusForm::DoDataExchange(CDataExchange* pDX){ CDialog::DoDataExchange(pDX);
/{{AFX_DATA_MAP(CBusForm)
/}}AFX_DATA_MAP <} BEGIN_MESSAGE_MAP(CBusForm, CDialog)
/{{AFX_MSG_MAP(CBusForm) ON_BN_CLICKED(Button_showBusType,
showBusType_onClick) ON_BN_CLICKED(Button_DeleteBus,
DeleteBus_onClick) ON_BN_CLICKED(Button_EditBus,
EditBus_onClick) ON_BN_CLICKED(Button_AddBus,
AddBus_onClick) ON_BN_CLICKED(IDOK,
OK_onClick) ON_WM_CLOSE() /}}AFX_MSG_MAP END_MESSAGE_MAP() /* ============================ <=====
User realization =====
<============================ */ CListBox*
pList_Bus; CComboBox*
pComboBox_BusType; CComboBox*
pComboBox_RaceInBus; /* ============================ <======
indexes & Funcn =====
<============================ */ oid ClearIndexes_pList_Bus_indexes(){ delete
[]pList_Bus_indexes,pLBiLen;
oid InitIndexes_pList_Bus_indexes(int len){
*(pLBiLen=new int)=len;} oid SetIndexes_pList_Bus_indexes(int idx,int
value){
oid ClearIndexes_pComboBox_BusType_indexes(){ delete
[]pComboBox_BusType_indexes,pCBBTiLen;
oid InitIndexes_pComboBox_BusType_indexes(int
len){
*(pCBBTiLen=new int)=len;} oid SetIndexes_pComboBox_BusType_indexes(int
idx,int value){
oid ClearIndexes_pComboBox_RaceInBus_indexes(){ delete
[]pComboBox_RaceInBus_indexes,pCBRIBiLen;
oid InitIndexes_pComboBox_RaceInBus_indexes(int
len){
*(pCBRIBiLen=new int)=len;} oid SetIndexes_pComboBox_RaceInBus_indexes(int
idx,int value){
/* ============================ <======
............... =====
<============================ */ oid Load_List_Bus(){ Load_List("SELECT
Bus.bus_ID,Trim(Str(Bus.bus_ID))+') '+Race.description+' - '+Type.name FROM
Type INNER JOIN (Race INNER JOIN Bus ON Race.race_ID = Bus.race_ID) ON
Type.busType_ID = Bus.busType_ID ORDER BY Trim(Str(Bus.bus_ID))+')
'+Race.description+' - '+Type.name","[bus_ID]&,[Expr1001]$",
ClearIndexes_pList_Bus_indexes, InitIndexes_pList_Bus_indexes, SetIndexes_pList_Bus_indexes);} oid Load_ComboBox_BusType(){ Load_List("SELECT
Type.* FROM Type","[busType_ID]&,[name]$",
ClearIndexes_pComboBox_BusType_indexes, InitIndexes_pComboBox_BusType_indexes, SetIndexes_pComboBox_BusType_indexes);} oid Load_ComboBox_RaceInBus(){ Load_List("SELECT
Race.race_ID,Trim(Str(Race.race_ID))+') '+Race.description FROM
Race","[race_ID]&,[Expr1001]$",
ClearIndexes_pComboBox_RaceInBus_indexes, InitIndexes_pComboBox_RaceInBus_indexes, SetIndexes_pComboBox_RaceInBus_indexes);} bool IsSelected_BusForm(){
AfxMessageBox("Nothing
selected!"); return
0;} return
1;} bool IsSelected_List_Bus(){ AfxMessageBox("Nothing
selected!"); return
0;} return
1;} oid setCurSel_List_Bus(int fictionIndex){
return;}} /* ============================ <======
Add Edit Remove =====
<============================ */ oid CBusForm::AddBus_onClick(){ /
>>> /
>>> CString
insertSql="INSERT INTO Bus (busType_ID,race_ID) Values($$1,$$2)"; DB.ExecuteSQL(insertSql); Load_List_Bus(); / ::: RS=new
CMyRecordset(&DB); CString
getNewIdSql="SELECT TOP 1 Bus.bus_ID FROM Bus WHERE Bus.busType_ID=$$1 AND
Bus.race_ID=$$2 ORDER BY Bus.bus_ID DESC"; RS->Open(getNewIdSql,"[bus_ID]&"); RS->MoveFirst(); RS->Close(); delete
RS; oid CBusForm::EditBus_onClick(){ /
>>> / >>> CString
updateSql="UPDATE Bus SET Bus.busType_ID=$$1,Bus.race_ID=$$2 WHERE
Bus.bus_ID=$$3"; DB.ExecuteSQL(updateSql); Load_List_Bus(); oid CBusForm::DeleteBus_onClick(){ /
>>> /
>>> CString
deleteSql="DELETE Bus.*, Bus.bus_ID FROM Bus WHERE Bus.bus_ID=$$$"; deleteSql.Replace("$$$",toString(cID)); DB.ExecuteSQL(deleteSql); Load_List_Bus(); // :::
/* ============================ <===
OnInitDialog OnClose ===
<============================ */ oid
CBusForm::OK_onClick(){SendMessage(WM_CLOSE,0,0);} BOOL
CBusForm::OnInitDialog(){CDialog::OnInitDialog(); /
>>>
/
>>> Load_List_Bus(); Load_ComboBox_BusType(); Load_ComboBox_RaceInBus(); /
>>> return
TRUE;} oid CBusForm::OnClose(){CDialog::OnClose(); ClearIndexes_pList_Bus_indexes(); ClearIndexes_pComboBox_BusType_indexes(); ClearIndexes_pComboBox_RaceInBus_indexes();} oid CBusForm::showBusType_onClick(){ CTypeForm
typeForm; Load_ComboBox_BusType();} CBusForm.h #if !defined(AFX_CBUSFORM_H__15C9D50F_B1DF_4489_9E98_8BAF03968B1A__INCLUDED_) #define
AFX_CBUSFORM_H__15C9D50F_B1DF_4489_9E98_8BAF03968B1A__INCLUDED_ #if _MSC_VER > 1 #pragma once #endif // _MSC_VER > 1 // CBusForm.h : header file // ///////////////////////////////////////////////////////////////////////////// // CBusForm dialog class CBusForm : public CDialog { // Construction public: CBusForm(CWnd*
pParent = NULL); / standard
constructor // Dialog Data /{{AFX_DATA(CBusForm) /
NOTE: the ClassWizard will add data members here /}}AFX_DATA // Overrides /
ClassWizard generated virtual function overrides /{{AFX_VIRTUAL(CBusForm)
/}}AFX_VIRTUAL // Implementation protected: /
Generated message map functions /{{AFX_MSG(CBusForm) /}}AFX_MSG DECLARE_MESSAGE_MAP() }; //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional
declarations immediately before the previous line. #endif // !defined(AFX_CBUSFORM_H__15C9D50F_B1DF_4489_9E98_8BAF03968B1A__INCLUDED_)
CMainForm.cpp #include "stdafx.h" #include "../main.h" #include "CMainForm.h" #include "CAboutForm.h" #include "CTimeForm.h" #include "CStationForm.h" #include "CPathForm.h" #include "CRaceForm.h" #include "CBusForm.h" #include "../ExLibrary/CMyRecordset.h" CMainForm::CMainForm(CWnd*
pParent):CDialog(CMainForm::IDD, pParent){
/{{AFX_DATA_INIT(CMainForm)
/}}AFX_DATA_INIT <} oid CMainForm::DoDataExchange(CDataExchange*
pDX){ CDialog::DoDataExchange(pDX);
/{{AFX_DATA_MAP(CMainForm)
/}}AFX_DATA_MAP <} BEGIN_MESSAGE_MAP(CMainForm, CDialog)
/{{AFX_MSG_MAP(CMainForm) ON_BN_CLICKED(Button_showTime,
showTime_onClick) ON_BN_CLICKED(Button_showStation,
showStation_onClick) ON_BN_CLICKED(Button_showPath,
showPath_onClick) ON_BN_CLICKED(Button_showAbout,
showAbout_onClick) ON_BN_CLICKED(Button_showRace,
showRace_onClick) ON_BN_CLICKED(Button_showBus,
showBus_onClick) /}}AFX_MSG_MAP END_MESSAGE_MAP() /* ============================ <=====
User realization =====
<============================ */ oid CMainForm::showTime_onClick(){ CTimeForm
timeForm; oid CMainForm::showStation_onClick(){ CStationForm
stationForm; oid CMainForm::showPath_onClick(){ CPathForm
pathForm;
oid CMainForm::showAbout_onClick(){ CAboutForm
aboutForm; oid CMainForm::showRace_onClick(){ CRaceForm
raceForm; raceForm.DoModal();} oid CMainForm::showBus_onClick(){ CBusForm
busForm; BOOL CMainForm::OnInitDialog(){ CDialog::OnInitDialog(); /
>>> DB.Open("ODBC;DSN=");} CString
str; AfxMessageBox(str);
/
>>> return
TRUE;} CMainForm.h #if
!defined(AFX_CMAINFORM_H__43C7FDB1_2162_4824_BBAC_EAF31944B6FB__INCLUDED_) #define
AFX_CMAINFORM_H__43C7FDB1_2162_4824_BBAC_EAF31944B6FB__INCLUDED_ #if _MSC_VER > 1 #pragma once #endif // _MSC_VER > 1 // CMainForm.h : header file // ///////////////////////////////////////////////////////////////////////////// // CMainForm dialog class CMainForm : public CDialog { // Construction public: CMainForm(CWnd*
pParent = NULL); / standard
constructor // Dialog Data /{{AFX_DATA(CMainForm) /
NOTE: the ClassWizard will add data members here /}}AFX_DATA // Overrides /
ClassWizard generated virtual function overrides /{{AFX_VIRTUAL(CMainForm)
/}}AFX_VIRTUAL // Implementation protected: /
Generated message map functions /{{AFX_MSG(CMainForm) /}}AFX_MSG DECLARE_MESSAGE_MAP() }; //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional
declarations immediately before the previous line. #endif //
!defined(AFX_CMAINFORM_H__43C7FDB1_2162_4824_BBAC_EAF31944B6FB__INCLUDED_) CPathForm.cpp #include "stdafx.h" #include "../main.h" #include "CPathForm.h" #include "../ExLibrary/CMyRecordset.h" CString
IsEmpty_CEdit(CEdit* ctrl); CPathForm::CPathForm(CWnd*
pParent):CDialog(CPathForm::IDD,pParent){
/{{AFX_DATA_INIT(CPathForm)
/}}AFX_DATA_INIT <} oid CPathForm::DoDataExchange(CDataExchange*
pDX){ CDialog::DoDataExchange(pDX);
/{{AFX_DATA_MAP(CPathForm) /}}AFX_DATA_MAP <} BEGIN_MESSAGE_MAP(CPathForm, CDialog)
/{{AFX_MSG_MAP(CPathForm) ON_BN_CLICKED(Button_AddPath,
AddPath_onClick) ON_BN_CLICKED(Button_EditPath,
EditPath_onClick) ON_BN_CLICKED(Button_DeletePath,
DeletePath_onClick) ON_BN_CLICKED(IDOK,
OK_onClick) ON_WM_CLOSE() /}}AFX_MSG_MAP END_MESSAGE_MAP() /* ============================ <=====
User realization =====
<============================ */ CListBox*
pList_Pathes; CComboBox*
pComboBox_Station1; CComboBox*
pComboBox_Station2; CEdit*
pEdit_pathTime; /* ============================ <======
indexes & Funcn =====
<============================ */ oid ClearIndexes_pList_Pathes_indexes(){ delete
[]pList_Pathes_indexes,pLPiLen;
oid InitIndexes_pList_Pathes_indexes(int len){
*(pLPiLen=new int)=len;} oid ClearIndexes_pComboBox_Stations_indexes(){ delete
[]pComboBox_Stations_indexes,pCBSiLen;
oid InitIndexes_pComboBox_Stations_indexes(int
len){
*(pCBSiLen=new int)=len;} /* ============================ <======
............... =====
<============================ */ oid Load_ComboBox_Stations(){
RS=new
CMyRecordset(&DB); RS->Open("SELECT
Station.* FROM Station","[station_ID]&,[name]$"); RS->DefineRealCount(); ClearIndexes_pComboBox_Stations_indexes(); InitIndexes_pComboBox_Stations_indexes(RS->Count);
RS->MoveNext();}} RS->Close(); delete
RS;} oid Load_List_Pathes(){
RS=new
CMyRecordset(&DB); RS->Open("SELECT
Path.path_ID, Station_1.name+' <-> '+Station_2.name+' -
('+Trim(Str(Path.time))+' min)' FROM Station AS Station_2 INNER JOIN (Station AS
Station_1 INNER JOIN Path ON Station_1.station_ID = Path.[start/end
station_ID]) ON Station_2.station_ID = Path.[end/start station_ID] ORDER BY
Station_1.name,Station_2.name,Path.time","[path_ID]&,[Expr1001]$"); RS->DefineRealCount(); ClearIndexes_pList_Pathes_indexes(); InitIndexes_pList_Pathes_indexes(RS->Count);
RS->MoveNext();}} RS->Close(); delete
RS;} bool IsSelected_PathStations(){
AfxMessageBox("Nothing
selected!"); return
0;} return
1;} bool IsSelected_List_Pathes(){ AfxMessageBox("Nothing
selected!"); return
0;} return
1;} oid setCurSel_PathStations(int fictionIndex){
return;}} /* ============================ <======
Add Edit Remove =====
<============================ */ oid CPathForm::AddPath_onClick(){ CString
newValue; /
>>> /
>>> AfxMessageBox("Path
can't be cycled!"); return;} /
>>> CString
prepSql="SELECT Path.path_ID FROM Path WHERE (Path.[start/end
station_ID]=$$1 OR Path.[start/end station_ID]=$$2) AND (Path.[end/start
station_ID]=$$1 OR Path.[end/start station_ID]=$$2) AND (Path.time=$$3)";
/
>>> CString
insertSql="INSERT INTO Path ([start/end station_ID],[end/start
station_ID],[time]) Values($$1,$$2,$$3)"; DB.ExecuteSQL(insertSql); Load_List_Pathes();
/ ::: RS=new
CMyRecordset(&DB); CString
getNewIdSql="SELECT Path.path_ID FROM Path WHERE Path.[start/end
station_ID]=$$1 AND Path.[end/start station_ID]=$$2 AND Path.time=$$3"; RS->Open(getNewIdSql,"[path_ID]&"); RS->MoveFirst(); RS->Close(); delete
RS; oid CPathForm::EditPath_onClick(){ /
>>> CString
newValue; /
>>>; /
>>> /
>>> AfxMessageBox("Path
can't be cycled!"); return;} /
>>> CString
prepSql="SELECT Path.path_ID FROM Path WHERE (Path.[start/end
station_ID]=$$1 OR Path.[start/end station_ID]=$$2) AND (Path.[end/start
station_ID]=$$1 OR Path.[end/start station_ID]=$$2) AND (Path.time=$$3);";
/
>>> CString
updateSql="UPDATE Path SET Path.[start/end station_ID]=$$1,
Path.[end/start station_ID]=$$2, Path.[time]=$$3 WHERE Path.path_ID=$$4"; DB.ExecuteSQL(updateSql); Load_List_Pathes();
oid CPathForm::DeletePath_onClick(){