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

C++ 对象内省——(枚举类属性)

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.67/5 (3投票s)

2002年11月15日

2分钟阅读

viewsIcon

62565

downloadIcon

391

C++ 中枚举类属性。

引言

你可能使用过允许你检查对象以确定对象在运行时包含哪些属性的编程语言(FoxPro、Perl 等)。如果需要编写通用的序列化例程,此功能非常有用。如果你使用 C++ 编程,你可能也知道这种内省功能是缺失的。

使用代码

我尝试创建一系列宏和类,它们将允许你在运行时暴露类的属性,而无需对现有代码进行大量更改。为此,你只需要从 CExposeAttributes 继承你的类,并在类的构造函数中为每个属性添加一行代码。当然,我做了一个很大的假设。这个假设是,你已经为所有属性实现了 Get/Set 方法。CExposeAttributes 的工作原理是维护一个指向这些 Get/Set 方法的函数指针列表。这暴露了类的属性,但仅通过公共方法。此外,我仅实现了对以下数据类型的支持:longdoubleCStringCGuidboolLPCTSTRGet/Set 方法必须符合以下函数签名

//
    long:
        YourSetFunction(long l);
        long YourGetFunction() const;
    double:
        YourSetFunction(double l);
        double YourGetFunction() const;
    bool:
        YourSetFunction(bool l);
        bool YourGetFunction() const;
    LPCTSTR:
        YourSetFunction(LPCTSTR l);
        LPCTSTR YourGetFunction() const;
    CString:
        YourSetFunction(const CString& l);
        CString YourGetFunction() const;
    CGuid:
        YourSetFunction(const CGuid& l);
        CGuid YourGetFunction() const;

如果你坚持使用其他 Get/Set 方法标准,则需要修改或添加对 CGetAttributeCSetAttribute 中函数指针 typedef 的支持。代码 (serialize.h) 中提供了有关添加对其他数据类型支持的说明。

//
//SAMPLE Class


class CSampleAttribute : public CXMLSerialization,
                 CExposeAttributes<csampleattribute>
{
public:
    CSampleAttribute();
    virtual ~CSampleAttribute();

    void SetName(LPCTSTR sName){m_sName=sName;};
    LPCTSTR GetName() const {return m_sName;};

    void SetSize(double dSize){m_dSize=dSize;};
    double GetSize() const {return m_dSize;};

    void SetLength(long lLength){m_lLength=lLength;};
    long GetLength() const {return m_lLength;};

    void SetID(const CGuid& oID){m_ID=oID;};
    CGuid GetID() const {return m_ID;};

    bool Save(MSXML2::IXMLDOMElementPtr& pParentElement);
    bool Load(MSXML2::IXMLDOMElementPtr& pElement,const CGuid& oID);

private:
    CString m_sName;
    double m_dSize;
    long m_lLength;
    CGuid m_ID;
};
</csampleattribute>

假设你已经定义了 Get/Set 方法,你就可以声明属性了。为此,在类的构造函数中使用以下宏之一

//
CSampleAttribute::CSampleAttribute()
{
    //Declare all of the attributes by identifying 
    //a name and the corresponding Set/Get methods
    SET_CGUID_ATTRIBUTE(CSampleAttribute,"ID",SetID,GetID);
    SET_LPCTSTR_ATTRIBUTE(CSampleAttribute,"Name",SetName,GetName);
    SET_LONG_ATTRIBUTE(CSampleAttribute,"Length",SetLength,GetLength);
    SET_DOUBLE_ATTRIBUTE(CSampleAttribute,"Size",SetSize,GetSize);
}

就是这样!你的类现在有几个方法,可以让你枚举它的所有属性。调用 GetGetAttributesGetSetAttributes 将返回一个 CGetAttributeCSetAttribute 列表。你可以编写可以枚举任何对象并读取/写入其属性的序列化类。我包含了一个名为 CXMLSerialization 的示例类。如果你从 CXMLSerialization 继承你的类,你将继承两种方法

virtual bool Save(MSXML2::IXMLDOMElementPtr& pParentElement) =0;
virtual bool Load(MSXML2::IXMLDOMElementPtr& pElement, const CGuid& oID) =0;

重写这些方法,以允许你的类将它的属性写入 XML 元素。

//
bool CSampleAttribute::Save(MSXML2::IXMLDOMElementPtr& pParentElement)
{
    //Override the save method of CXMLSerialization
    ASSERT(pParentElement!=NULL);

    //Don't save if we don't need to
    if (GetDirty()== false)
        return true;

    CString sXPATH;
    CXMLAttribute<csampleattribute> oAttribute;

    //Find the correct element (if it exists)
    sXPATH.Format("%s[@%s='%s']","SampleAttribute", 
                          "ID",GetID().CStrValUCase());
    MSXML2::IXMLDOMElementPtr pCur = 
        pParentElement->selectSingleNode((LPCTSTR)sXPATH);
    if (pCur == NULL)
    {
      //It didn't exists, create the element
      pCur = 
       pParentElement->GetownerDocument()->createElement("SampleAttribute");
      pParentElement->appendChild(pCur);
    }

    oAttribute.Save(pCur,this,this);
    SetDirty(false);
    return true;
}
bool CSampleAttribute::Load
   (MSXML2::IXMLDOMElementPtr& pElement,const CGuid& oID)
{
    ASSERT(pElement!=NULL);
    CXMLAttribute<csampleattribute> oAttribute;

    oAttribute.Load(pElement,this,this);
    SetDirty(false);
    return true;
}
</csampleattribute></csampleattribute>

CXMLAttribute 知道如何将所有类型的属性加载和保存到 XML 以及从 XML 加载和保存。可以轻松创建一个类似的类来读/写到关系数据库。

© . All rights reserved.