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






2.67/5 (3投票s)
2002年11月15日
2分钟阅读

62565

391
C++ 中枚举类属性。
引言
你可能使用过允许你检查对象以确定对象在运行时包含哪些属性的编程语言(FoxPro、Perl 等)。如果需要编写通用的序列化例程,此功能非常有用。如果你使用 C++ 编程,你可能也知道这种内省功能是缺失的。
使用代码
我尝试创建一系列宏和类,它们将允许你在运行时暴露类的属性,而无需对现有代码进行大量更改。为此,你只需要从 CExposeAttributes
继承你的类,并在类的构造函数中为每个属性添加一行代码。当然,我做了一个很大的假设。这个假设是,你已经为所有属性实现了 Get
/Set
方法。CExposeAttributes
的工作原理是维护一个指向这些 Get
/Set
方法的函数指针列表。这暴露了类的属性,但仅通过公共方法。此外,我仅实现了对以下数据类型的支持:long
、double
、CString
、CGuid
、bool
和 LPCTSTR
。Get
/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
方法标准,则需要修改或添加对 CGetAttribute
和 CSetAttribute
中函数指针 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); }
就是这样!你的类现在有几个方法,可以让你枚举它的所有属性。调用 GetGetAttributes
或 GetSetAttributes
将返回一个 CGetAttribute
或 CSetAttribute
列表。你可以编写可以枚举任何对象并读取/写入其属性的序列化类。我包含了一个名为 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 加载和保存。可以轻松创建一个类似的类来读/写到关系数据库。