C++ 面向对象数据库生成器






4.38/5 (7投票s)
1999年11月18日
3分钟阅读

145345

1203
本项目是一个代码生成器,
这里展示了为面向对象数据库管理生成 CObject 和 CObList 派生类的应用程序。
最近我一直在进行的一些项目大量使用了 CObject 派生类进行封装数据管理(面向对象数据库)。在创建了几个数据对象之后,您开始意识到可以自动化大部分代码的生成。该项目是一个代码生成器,用于生成具有序列化和受保护数据成员的 CObject 派生数据类。
除了 CObject 派生数据类之外,该应用程序还可以生成一个排序的 CObList 派生类来保存您的数据对象。对于您创建的每个数据对象,您可以指定索引成员。然后,对象列表将按照这些索引成员进行排序。当您将一个新对象添加到列表中时,CObList 派生类确保它被添加到列表中的正确位置。
此代码生成器的特点
- 生成 CObject 派生类和 CObList 派生类,以将对象保存在排序列表中
- 类名遵循所选文件名
- 变量根据匈牙利命名法前缀分配数据类型
- 包括序列化代码
- 所有数据成员都是受保护的,并通过 Get/Set 内联函数访问
- 包括构造函数中的初始化代码
- 包括用于复制对象属性的成员函数
- 包括上次修改日期/时间
- 包括 Dump 和 AssertValid 函数
- 对象列表可以按多个字段排序
- 目前,您只能创建一个“键”值,尽管稍微动点脑筋,您可以使用该应用程序多次生成多个 CObList 派生类,并允许使用多个列表。
- 如果您更改了一个关键字段的值,列表不会重新排序。虽然在 CObList 派生类中添加一个排序函数很简单,但困难在于您的应用程序中可能存在多个 CObList 派生类的实例,所有这些实例都包含指向相同对象的指针。因此,如果一个对象更改了一个关键字段,您必须重新排序所有这些列表。问题是如何最好地跟踪所有这些列表的位置。我还没有找到答案!
- 将新对象添加到列表的函数没有针对排序列表进行很好的优化
- 没有复制构造函数
使用代码生成器
1. 为源文件输出选择一个文件名。您的头文件将具有相同的名称,但带有“.h”扩展名。此外,类名是从文件名派生的,例如 Example.cpp 将生成一个名为“CExample”的类,并且 COblist 派生类将是 CExampleList。请注意,代码生成器将覆盖任何现有文件。
2. 输入类的成员数据成员名称。数据类型由匈牙利命名法前缀确定。程序使用以下前缀(这些很容易更改)
- dt -- COleDateTime
- str -- CStirng
- n -- int
- f -- double(不是 FLAG!)
- b -- BOOL
- rgb -- COLORREF
如果将索引列表留空,应用程序将不会生成 CObList 派生类。仅生成 CObject 派生类。
3. 单击“生成”按钮生成源文件和头文件。
代码生成器使用我自己的编程风格生成代码,因此您可能需要对其进行调整以更紧密地遵循您自己的风格。
/////////////////////////////////////////////////////////////////////////// // CExample -- Interface for CExample object #ifndef __EXAMPLE_H__ #define __EXAMPLE_H__ class CExample; // This ObList derived class is generated if you add index member functions class CExampleList : public CObList { public: CExample* FindEntry(COleDateTime dtDate, int nOrder, CString strLocationID); POSITION FindEntryPos(COleDateTime dtDate, int nOrder, CString strLocationID); POSITION FindEntryPosBruteForce(COleDateTime dtDate, int nOrder, CString strLocationID); void AddExample(CExample* pNew); void RemoveExample(COleDateTime dtDate, int nOrder, CString strLocationID); virtual void Serialize(CArchive& ar); void ClearAndDelete(); }; // Here is the CObject derived class class CExample : public CObject { // construction public: DECLARE_SERIAL(CExample); CExample(); CExample(COleDateTime dtDate, int nOrder, CString strLocationID); ~CExample(); // Attributes public: protected: COleDateTime m_dtDate; int m_nOrder; CString m_strLocationID; CString m_strCustomerName; COleDateTime m_dtBirthDate; COLORREF m_rgbColor; COleDateTime m_dtCreated; COleDateTime m_dtLastModified; // Operations public: virtual void Serialize(CArchive& ar); void Duplicate(CExample* pSource); void Clear(); int Compare(COleDateTime dtDate, int nOrder, CString strLocationID); int Compare(CExample* pTest); // Diagnostics #ifdef _DEBUG void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif // inlines public: inline void SetDate(COleDateTime dtNew) { m_dtLastModified = COleDateTime::GetCurrentTime(); m_dtDate = dtNew; } inline COleDateTime GetDate() {; return m_dtDate; } inline void SetOrder(int nNew) { m_dtLastModified = COleDateTime::GetCurrentTime(); m_nOrder = nNew; } inline int GetOrder() {; return m_nOrder; } inline void SetLocationID(CString strNew) { m_dtLastModified = COleDateTime::GetCurrentTime(); m_strLocationID = strNew; m_strLocationID.FreeExtra(); } inline CString GetLocationID() {; return m_strLocationID; } inline void SetCustomerName(CString strNew) { m_dtLastModified = COleDateTime::GetCurrentTime(); m_strCustomerName = strNew; m_strCustomerName.FreeExtra(); } inline CString GetCustomerName() {; return m_strCustomerName; } inline void SetBirthDate(COleDateTime dtNew) { m_dtLastModified = COleDateTime::GetCurrentTime(); m_dtBirthDate = dtNew; } inline COleDateTime GetBirthDate() {; return m_dtBirthDate; } inline void SetColor(COLORREF rgbNew) { m_dtLastModified = COleDateTime::GetCurrentTime(); m_rgbColor = rgbNew; } inline COLORREF GetColor() {; return m_rgbColor; } inline void SetCreated(COleDateTime dtNew) { m_dtLastModified = COleDateTime::GetCurrentTime(); m_dtCreated = dtNew; } inline COleDateTime GetCreated() {; return m_dtCreated; } inline void SetLastModified(COleDateTime dtNew) { m_dtLastModified = COleDateTime::GetCurrentTime(); m_dtLastModified = dtNew; } inline COleDateTime GetLastModified() {; return m_dtLastModified; } }; #endif // #define __EXAMPLE_H__
这是使用该程序根据上图配置生成的源文件代码。绿色注释是我为这篇文章添加的,不是由程序生成的。
/////////////////////////////////////////////////////////////////////////// // CExample -- Implementation for CExample object #include "stdafx.h" #include "Example.h" IMPLEMENT_SERIAL(CExample, CObject, 0); //////////////////////////////////////////////////////////// // CExampleList class members // This function finds an object based on the index values provided // it returns a pointer to the object CExample* CExampleList::FindEntry(COleDateTime dtDate, int nOrder, CString strLocationID) { POSITION Pos = FindEntryPos(dtDate, nOrder, strLocationID); if (Pos == NULL) return NULL; return (CExample*)GetAt(Pos); } // This function finds the POSITION of an object based on the // key values provided POSITION CExampleList::FindEntryPos(COleDateTime dtDate, int nOrder, CString strLocationID) { POSITION Pos; CExample* pExample; div_t divresult; int nCurrent, nHigh, nLow, nCompareResult, nLastCurrent = -1; nLow = 0; nHigh = GetCount(); divresult = div(nHigh - nLow, 2); nCurrent = nLow + divresult.quot; if (nHigh <= 0) goto l_NotFound; // no items in the list while (TRUE) { Pos = FindIndex(nCurrent); pExample = (CExample*)GetAt(Pos); nCompareResult = pExample->Compare(dtDate, nOrder, strLocationID); if (nCompareResult == 0) { return Pos; } if (nCompareResult > 0) // we are in lower half of test range { nHigh = nCurrent; divresult = div(nHigh - nLow, 2); nCurrent = nLow + divresult.quot; } else // we are in upper half of test range { nLow = nCurrent; divresult = div(nHigh - nLow, 2); nCurrent = nLow + divresult.quot; } if (nCurrent == nLastCurrent) goto l_NotFound; nLastCurrent = nCurrent; } l_NotFound:; // The search above is optimized to work on a pre-sorted list // To make sure it works, we search the list through brute force. If we didn't // find it above, we shouldn't find it below #ifdef _DEBUG Pos = FindEntryPosBruteForce(dtDate, nOrder, strLocationID); if (Pos != NULL) TRACE("Searching algorithm failed\n"); #endif return NULL; } // end of FindEntryPos // This function searches the list for an object // based on the key values provided. However it does not require // a pre-sorted list. You should implement this class so that this function // is not required in the release version POSITION CExampleList::FindEntryPosBruteForce(COleDateTime dtDate, int nOrder, CString strLocationID) { CExample* pExample; POSITION Pos = GetHeadPosition(); while (Pos) { pExample = (CExample*)GetNext(Pos); if (pExample->Compare(dtDate, nOrder, strLocationID) == 0) { return Pos; } } return NULL; } // end of FindEntryPosBruteForce // This function adds an object to the list and places it in // it's proper position based on the value of the key fields void CExampleList::AddExample(CExample* pNew) { CExample* pExample; int nCompareResult; POSITION Pos; // need to search through list and add in the proper sorted order ASSERT_VALID(pNew); ASSERT(Find(pNew) == NULL); // start from end because it is more likely to be added to the end Pos = GetTailPosition(); while (Pos) { pExample = (CExample*)GetAt(Pos); nCompareResult = pExample->Compare(pNew); ASSERT(nCompareResult != 0); if (nCompareResult == 0) return; if (nCompareResult == -1) { InsertAfter(Pos, pNew); return; } GetPrev(Pos); } AddHead(pNew); return; } void CExampleList::RemoveExample(COleDateTime dtDate, int nOrder, CString strLocationID) { POSITION Pos = FindEntryPos(dtDate, nOrder, strLocationID); if (Pos) RemoveAt(Pos); } // Function to serialize the list and all it's objects void CExampleList::Serialize(CArchive& ar) { // NOTE: Do not call the base class! DWORD dwVersion = 0x00000000; int n, nCount; POSITION Pos; CExample* pExample; if (ar.IsStoring()) { ar<<dwVersion; nCount = GetCount(); ar<<nCount; Pos = GetHeadPosition(); while (Pos) { pExample = (CExample*)GetNext(Pos); pExample->Serialize(ar); } } else { ar>>dwVersion; ASSERT(GetCount() == 0); ar>>nCount; for (n = 0; n < nCount; ++n) { pExample = new CExample(); if (pExample == NULL) THROW(new CMemoryException()); pExample->Serialize(ar); AddTail(pExample); } } } // end of Serialize // This function clears the list but also deletes the object. // Make sure you only delete the objects once! // If you have multiple instances of this list, only one should // ever call this function! void CExampleList::ClearAndDelete() { CExample* pExample; POSITION Pos = GetHeadPosition(); while (Pos) { pExample = (CExample*)GetNext(Pos); ASSERT_VALID(pExample); delete pExample; } RemoveAll(); } //////////////////////////////////////////////////////////// // CExample class members //////////////////////////////////////////// // CExample construction/destruction // Construction CExample::CExample() { Clear(); m_dtCreated = COleDateTime::GetCurrentTime(); } // If you create Index fields for your object, // the application will generate a second constructor with the index // fields as parameters CExample::CExample(COleDateTime dtDate, int nOrder, CString strLocationID) { Clear(); m_dtCreated = COleDateTime::GetCurrentTime(); m_dtDate = dtDate; m_nOrder = nOrder; m_strLocationID = strLocationID; } // Initialization void CExample::Clear() { m_dtDate = 0.0; m_nOrder = 0; m_strLocationID = _T(""); m_strCustomerName = _T(""); m_dtBirthDate = 0.0; m_rgbColor = 0; m_dtCreated = 0.0; m_dtLastModified = 0.0; } // Destruction CExample::~CExample() { } //////////////////////////////////////////// // CExample Diagnostics #ifdef _DEBUG void CExample::Dump(CDumpContext& dc) const { dc.SetDepth(1); dc <<"Date = " << m_dtDate; dc <<"Order = " << m_nOrder; dc <<"LocationID = " << m_strLocationID; dc <<"CustomerName = " << m_strCustomerName; dc <<"BirthDate = " << m_dtBirthDate; dc <<"Color = " << m_rgbColor; dc <<"Created = " << m_dtCreated; dc <<"LastModified = " << m_dtLastModified; } void CExample::AssertValid() const { CObject::AssertValid(); // TODO: Add validity checking here } #endif //////////////////////////////////////////// // CExample operations void CExample::Serialize(CArchive& ar) { DWORD dwVersion = 0x00000000; if (ar.IsStoring()) { ar<<dwVersion; ar<<m_dtDate<<m_nOrder<<m_strLocationID <<m_strCustomerName<<m_dtBirthDate<<m_rgbColor <<m_dtCreated<<m_dtLastModified; } else { ar>>dwVersion; ar>>m_dtDate>>m_nOrder>>m_strLocationID>>m_strCustomerName >>m_dtBirthDate>>m_rgbColor>>m_dtCreated>>m_dtLastModified; } CObject::Serialize(ar); } // end of Serialize // I prefer a duplicate function rather than a copy constructor void CExample::Duplicate(CExample* pSource) { m_dtDate = pSource->m_dtDate; m_nOrder = pSource->m_nOrder; m_strLocationID = pSource->m_strLocationID; m_strCustomerName = pSource->m_strCustomerName; m_dtBirthDate = pSource->m_dtBirthDate; m_rgbColor = pSource->m_rgbColor; m_dtCreated = pSource->m_dtCreated; m_dtLastModified = pSource->m_dtLastModified; } // end of Duplicate // To support the searching and sorting in the list // we must have a compare function to compare to objects based on their key fields // the function operates the same as CString::Compare int CExample::Compare(COleDateTime dtDate, int nOrder, CString strLocationID) { int nCompare; if (dtDate.m_status != COleDateTime::valid) return -1; if (m_dtDate < dtDate) return -1; if (m_dtDate > dtDate) return 1; if (m_nOrder < nOrder) return -1; if (m_nOrder > nOrder) return 1; nCompare = m_strLocationID.Compare(strLocationID); if (nCompare < 0) return -1; if (nCompare > 0) return 1; return 0; } int CExample::Compare(CExample* pTest) { return Compare(pTest->GetDate(), pTest->GetOrder(), pTest->GetLocationID()); }
就是这样。我刚接触 OODB,所以对反馈和改进很感兴趣。