Смекни!
smekni.com

Моделирование структуры книги (стр. 2 из 3)

В приложении классы книги, раздела, главы и страницы унаследованы от CObject. Это необходимо для реализации механизма загрузки документа из файла – метод Serialize() в этих классах перегружается также, как и в классе документа:

void CBookDoc::Serialize(CArchive& ar)

{

m_Book.Serialize(ar);

}

Классы CRazdels, CGlavas и CPages унаследованы от класса CObArray. Поэтому для объектов этих классов можно вызывать все члены-функции, присущие классу массива объектов.

Объектная модель книги

Реализация объектной модели на языке программирования C++

Реализация класса книги

BookClass.h:

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

#include "Razdels.h"

class CBookClass;

extern void RenewTree(CTreeCtrl*,CBookClass*);

extern void RenewList(CListCtrl*,CBookClass*);

class CBookClass : public CObject

{

DECLARE_SERIAL(CBookClass)

private:

CRazdels m_Razdels;

CPtrArray m_pPages;

CTreeCtrl* pTreeCtrl;

CListCtrl* pListCtrl;

CString m_Name;

WORD m_ActivePage;

void RenewCtrls()

{

RenewTree(pTreeCtrl,this);

RenewList(pListCtrl,this);

}

public:

CRazdels* GetRazdels()

{

return &m_Razdels;

}

CPtrArray* GetPages()

{

return &m_pPages;

}

void SetTreeCtrl(CTreeCtrl* TreeCtrl)

{

pTreeCtrl=TreeCtrl; }

void SetListCtrl(CListCtrl* ListCtrl)

{

pListCtrl=ListCtrl;

}

CString* GetName()

{

return &m_Name;

}

WORD GetActivePage()

{

return m_ActivePage;

}

void SetActivePage(WORD Page)

{

m_ActivePage=Page;

RenewList(pListCtrl,this);

}

void SetPreviousActivePage()

{

if (m_ActivePage>0)

{

m_ActivePage--;

RenewCtrls();

}

}

void SetNextActivePage()

{

if (m_ActivePage+1<m_pPages.GetSize())

{

m_ActivePage++;

RenewCtrls();

}

}

CBookClass();

~CBookClass();

void Serialize(CArchive&);

};

BookClass.cpp:

#include "stdafx.h"

#include "BookClass.h"

IMPLEMENT_SERIAL(CBookClass,CObject,0)

CBookClass::CBookClass()

{

m_ActivePage=0;

}

CBookClass::~CBookClass()

{

m_Razdels.DeleteRazdels();

}

void CBookClass::Serialize(CArchive& ar)

{

m_Razdels.DeleteRazdels();

m_pPages.RemoveAll();

m_ActivePage=0;

CObject::Serialize(ar);

if (ar.IsLoading())

{

ar>>m_Name;

WORD Count,Counter;

ar>>Count;

for(Counter=0;Counter<Count;Counter++)

{

CRazdel* Razdel=new CRazdel;

Razdel->Serialize(ar);

m_Razdels.Add(Razdel);

}

for(Counter=0;Counter<m_Razdels.GetSize();Counter++)

{

CRazdel* Razdel=(CRazdel*)m_Razdels.GetAt(Counter);

for(WORD Counter2=0;Counter2<Razdel->GetGlavas()->GetSize();Counter2++)

{

CGlava* Glava=(CGlava*)Razdel->GetGlavas()->GetAt(Counter2);

for(WORD Counter3=0;Counter3<Glava->GetPages()->GetSize();Counter3++)

m_pPages.Add(Glava->GetPages()->GetAt(Counter3));

}

}

}

}

Razdels.h:

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

#include "Razdel.h"

class CRazdels : public CObArray

{

public:

void DeleteRazdels();

};

Razdels.cpp:

#include "stdafx.h"

#include "Razdels.h"

void CRazdels::DeleteRazdels()

{

WORD Counter;

for(Counter=0;Counter<GetSize();Counter++)

{

CRazdel* Razdel=(CRazdel*)GetAt(Counter);

Razdel->GetGlavas()->DeleteGlavas();

delete Razdel;

}

RemoveAll();

}

Razdel.h:

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

#include "Glavas.h"

class CRazdel : public CObject

{

DECLARE_SERIAL(CRazdel)

private:

CGlavas m_Glavas;

CString m_Name;

WORD m_FirstGlava;

WORD m_LastGlava;

WORD m_FirstPage;

WORD m_LastPage;

public:

CGlavas* GetGlavas()

{

return &m_Glavas;

}

CString* GetName()

{

return &m_Name;

}

WORD GetFirstGlava()

{

return m_FirstGlava;

}

void SetFirstGlava(WORD FirstGlava)

{

m_FirstGlava=FirstGlava;

}

WORD GetLastGlava()

{

return m_LastGlava;

}

void SetLastGlava(WORD LastGlava)

{

m_LastGlava=LastGlava;

}

WORD GetFirstPage()

{

return m_FirstPage;

}

void SetFirstPage(WORD FirstPage)

{

m_FirstPage=FirstPage;

}

WORD GetLastPage()

{

return m_LastPage;

}

void SetLastPage(WORD LastPage)

{

m_LastPage=LastPage;

}

CRazdel(){};

void Serialize(CArchive&);

};

Razdel.cpp:

#include "stdafx.h"

#include "Razdel.h"

IMPLEMENT_SERIAL(CRazdel,CObject,0)

void CRazdel::Serialize(CArchive& ar)

{

CObject::Serialize(ar);

if (ar.IsLoading())

{

ar>>m_Name>>m_FirstGlava>>m_LastGlava>>m_FirstPage>>

m_LastPage;

WORD Count,Counter;

ar>>Count;

for(Counter=0;Counter<Count;Counter++)

{

CGlava* Glava=new CGlava;

Glava->Serialize(ar);

m_Glavas.Add(Glava);

}

}

}

Glavas.h:

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

#include "Glava.h"

class CGlavas : public CObArray

{

public:

void DeleteGlavas();

};

Glavas.cpp:

#include "stdafx.h"

#include "Glavas.h"

void CGlavas::DeleteGlavas()

{

WORD Counter;

for(Counter=0;Counter<GetSize();Counter++)

{

CGlava* Glava=(CGlava*)GetAt(Counter);

Glava->GetPages()->DeletePages();

delete Glava;

}

RemoveAll();

}

Glava.h:

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

#include "Pages.h"

class CGlava : public CObject

{

DECLARE_SERIAL(CGlava)

private:

CPages m_Pages;

CString m_Name;

WORD m_FirstPage;

WORD m_LastPage;

public:

CPages* GetPages()

{

return &m_Pages;

}

CString* GetName()

{

return &m_Name;

}

WORD GetFirstPage()

{

return m_FirstPage; }

void SetFirstPage(WORD FirstPage)

{

m_FirstPage=FirstPage;

}

WORD GetLastPage()

{

return m_LastPage;

}

void SetLastPage(WORD LastPage)

{

m_LastPage=LastPage;

}

CGlava(){};

void Serialize(CArchive&);

};

Glava.cpp:

#include "stdafx.h"

#include "Glava.h"

IMPLEMENT_SERIAL(CGlava,CObject,0)

void CGlava::Serialize(CArchive& ar)

{

CObject::Serialize(ar);

if (ar.IsLoading())

{

ar>>m_Name>>m_FirstPage>>m_LastPage;

WORD Count,Counter;

ar>>Count;

for(Counter=0;Counter<Count;Counter++)

{

CPage* Page=new CPage;

Page->Serialize(ar);

m_Pages.Add(Page);

}

}

}

Pages.h:

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

#include "Page.h"

class CPages : public CObArray

{

public:

void DeletePages();

};

Pages.cpp:

#include "stdafx.h"

#include "Pages.h"

void CPages::DeletePages()

{

WORD Counter;

for(Counter=0;Counter<GetSize();Counter++)

{

CPage* Page=(CPage*)GetAt(Counter);

delete Page;

}

RemoveAll();

}

Page.h:

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

#define CountOfStrings 37

class CPage : public CObject

{

DECLARE_SERIAL(CPage)

private:

CString m_Strings[CountOfStrings];

CString m_Name;

HTREEITEM m_TreeItem;

public:

CString* GetString(BYTE Index)

{

return &m_Strings[Index];

}

CString* GetName()

{

return &m_Name;

}

HTREEITEM GetTreeItem()

{

return m_TreeItem;

}

void SetTreeItem(HTREEITEM TreeItem)

{

m_TreeItem=TreeItem;

}

CPage(){};

void Serialize(CArchive&);

};

Page.cpp:

#include "stdafx.h"

#include "Page.h"

IMPLEMENT_SERIAL(CPage,CObject,0)

void CPage::Serialize(CArchive& ar)

{

CObject::Serialize(ar);

if (ar.IsLoading())

{

ar>>m_Name;

BYTE Counter;

for(Counter=0;Counter<CountOfStrings;Counter++)

ar>>m_Strings[Counter];

}

}


Порождение объектов

В файле Book.cpp объявляется глобальная переменная – объект класса приложения CBookApp:

CBookApp theApp;

В перегруженной функции-члене InitInstance() класса CBookApp создаются объекты классов документа, окна и представления оглавления:

BOOL CBookApp::InitInstance()

{

CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate(

IDR_MAINFRAME,

RUNTIME_CLASS(CBookDoc),

RUNTIME_CLASS(CMainFrame),

RUNTIME_CLASS(CLeftView));

AddDocTemplate(pDocTemplate);

return TRUE;

}

Класс окна CMainFrame содержит защищенный атрибут класса CSplitterWnd, предоставляющий доступ к представлению страницы посредством вызова открытой член-функции класса CMainFrame:

class CMainFrame : public CFrameWnd

{

protected:

CSplitterWnd m_wndSplitter;

public:

CBookView* GetRightPane();

};

Объект класса книги является открытым атрибутом класса документа:

class CBookDoc : public CDocument

{

public:

CBookClass m_Book;

};

Все структурные элементы книги (разделы, главы и страницы) создаются в момент загрузки файла книги с диска через оператор new:

CRazdel* Razdel=new CRazdel;

m_Razdels.Add(Razdel);

Вызов операций

Вызов операций для объектов в C++ может быть организован двумя способами:

1) Если требуется вызвать операцию для переменной, являющейся объектом какого-либо класса, то используется оператор .*:

Object.MemberFunc();

2) Если переменная является указателем на объект класса, то доступ к методам, поддерживаемым данным классом, организовывается через оператор ->*:

pObject->MemberFunc();

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

CBookDoc* pDoc = GetDocument();

pDoc->m_Book.SetTreeCtrl(&refCtrl);

Если члены-функции вызываются внутри их класса, то вызов этих функций осуществляется напрямую без указания имени класса. Например, внутри функции CRazdels::DeleteRazdels() осуществляется вызов членов-функций, наследуемых от базового класса CObArray:

void CRazdels::DeleteRazdels()

{

WORD Counter;

for(Counter=0;Counter<GetSize();Counter++)

{

CRazdel* Razdel=(CRazdel*)GetAt(Counter);

Razdel->GetGlavas()->DeleteGlavas();

delete Razdel;

}

RemoveAll();

}

Использование наследования

Согласно концепции объектно-ориентированного программирования функция загрузки файла книги с диска должна быть инкапсулирована в самом классе CBookClass. Основные этапы создания класса, который может самостоятельно организовать сохранение-восстановление (в документации на MFC применяется термин serialize-сериализация) собственных членов-переменных перечислены ниже:

1.Объявить класс как производный от CObject.

2.В объявление класса включить макрос DECLARE_SERIAL.

3.В реализацию класса включить макрос IMPLEMENT_SERIAL.

4.Перегрузить метод Serialize(), унаследованный от базового класса.