65.9K
CodeProject 正在变化。 阅读更多。
Home

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

1999年11月18日

3分钟阅读

viewsIcon

145345

downloadIcon

1203

本项目是一个代码生成器, 用于为面向对象数据库管理生成 CObject 派生数据类。

Sample Image

这里展示了为面向对象数据库管理生成 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 派生类。列表将按照这些成员出现的顺序进行排序。索引也将用于比较对象,并将作为构造函数的参数提供。

如果将索引列表留空,应用程序将不会生成 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,所以对反馈和改进很感兴趣。

© . All rights reserved.