分享
 
 
 

利用宏给C++实现属性与“反射”

王朝c/c++·作者佚名  2006-02-01
窄屏简体版  字體: |||超大  

明天就要返校了,学校安装校园网估计又要等一个星期,郁闷,今天下午无聊,给C++实现了一个“反射”机制,仅限于对属性的反射。包括:枚举属性,访问属性。

在C++中原本不存在属性这个概念的,这么优秀的思想没有实现其实是很可惜的。

其实给C++实现反射,本身无形之中就会带来效率的降低,以及元数据的存在导致的体积的增大,但是使用得当,却可以减轻很多问题,总的来说,也有好的一面,应该积极开发与利用。C/C++的RTTI虽然支持的很少,但强大的宏依然是一把利剑。好好利用这把利剑,再强大的神都无法阻碍它的前进。

软件工业发展这么多年来,都普遍知道了大量使用全局变量不是好事。而面向对象程序设计的发明引入了一个概念,将数据封装到类中,从而能够更加方便的管理数据。但是,通常的C/C++之类的通过成员函数来修改/访问数据使得数据不便于管理。对数据的访问不够一致,这样和使用全局变量大同小异。而Delphi率先采用了一种“智能数据”封装技术,将对数据的访问提供了一种统一的方法,以便防止数据的滥用。

而在C++的成员函数中,通过方法提供对数据统一的访问也不是不可以实现,例如如下代码:

DWORD& CTest::ID()

{

return m_dwID;

}

这样,通过函数ID即可随时访问m_dwID,修改都可以。但是这样只是一个简单的实现,相对于C#中的getter, setter而言,还是幼稚了一点。而在managed C++中,引入了新的关键字__property,以便能让其生成的MSIL代码和其他语言生成的能够兼容,其实看来,似乎没有什么实际作用,只是在编译成managed code的时候加入一些元数据来描述其为属性的getter, setter:

__property DWORD get_ID()

{

return m_dwID;

}

所有支持强大RTTI的语言,都无一例外使用了一定元数据来描述一个属性。所以,依照这个思路,要给C++安装属性,就需要设计一个元数据结构,这么一个元数据结构至少要包含这些特性:属性名,属性类型,Getter函数,Setter函数,由于属性可能不止一个,所以采用链表来保存多个属性元数据结构,还要在元数据中加入指向下一个元数据的地址字段,由于属性可以不同为一个类型,所以这里使用模板结构,而这里假设属性方法的原形何Delphi中的属性read/write方法一样,setter有一个参数没返回值,getter没有参数有返回值。由于模板主要在编译期间给一些类或函数函数确定使用参数类型,在运行期间没有区别,所以作为链表节点,还需要一个关键部位和该结构一模一样的结构:

typedef struct tagCPropertyBase

{

LPCSTR szName;

LPCSTR szType;

tagCPropertyBase *lpNext;

}CPropertyBase;

所以模板结构开头也这个样子:

template<typename C,typename T>

struct CPropertyInfo

{

LPCSTR szName;

LPCSTR szType;

CPropertyBase *lpNext;

void (C::*Setter)(T);

T (C::*Getter)();

CPropertyInfo(LPCSTR szName,LPCSTR szType,void (C::*Setter)(T),T (C::*Getter)())

{

this->szName=szName;

this->szType=szType;

this->Setter=Setter;

this->Getter=Getter;

this->lpNext=NULL;

//初始化含有属性类的链表头节点

if(C::lpFirstProperty==NULL)

{

C::lpFirstProperty=(CPropertyBase*)this;

}

//将当前属性信息添加到链表结尾

if(C::lpLastProperty!=NULL)

{

C::lpLastProperty->lpNext=(CPropertyBase*)this;

}

C::lpLastProperty=(CPropertyBase*)this;

};

};

然后就是定义类属性的相关的宏和相关的函数,今天多写点代码少说点屁话,看我Blog的都差不多是看的懂的人,外行话就少说点:

用来确定链表头尾:

#define REFLECT_DECLARE() static CPropertyBase* lpFirstProperty; static CPropertyBase* lpLastProperty;

初始化链表头尾:

#define REFLECT_IMPLEMENT(C) CPropertyBase* C::lpFirstProperty=NULL; CPropertyBase* C::lpLastProperty=NULL;

定义属性元数据:

#define PROPERTY_DECLARE(C,T,P) static struct CPropertyInfo<C,T> Prop_##P; void set_##P(T); T get_##P();

初始化属性元数据:

#define PROPERTY_IMPLEMENT(C,T,P) struct CPropertyInfo<C,T> C::Prop_##P(#P,#T,C::set_##P,C::get_##P);

访问属性元数据:

#define PROPERTY(C,P) &(C::Prop_##P)

修改属性:

#define SET_PROP(O,P,V) (O->*P->Setter)(V)

读取属性:

#define GET_PROP(O,P) (O->*P->Getter)()

根据属性名查找属性:

template<typename C,typename T>

CPropertyInfo<C,T>* FindProperty(LPCSTR szName)

{

CPropertyBase* Item=C::lpFirstProperty;

while(Item)

{

if(!strcmp(Item->szName,szName))

return reinterpret_cast<CPropertyInfo<C,T>*>(Item);

Item=Item->lpNext;

}

return NULL;

}

修改属性:

template<typename C,typename T>

inline void SetProperty(C*Instance,CPropertyInfo<C,T>*Prop,T __value)

{

(Instance->*Prop->Setter)(__value);

}

读取属性:

template<typename C,typename T>

inline T GetProperty(C*Instance,CPropertyInfo<C,T>*Prop)

{

if(Prop->Getter)

return (Instance->*Prop->Getter)();

return (T)0;

}

来测试一下,定义一个包含属性的类:

class CTest

{

private:

int m_ID;

char m_Name[100];

public:

REFLECT_DECLARE();

PROPERTY_DECLARE(CTest,int,ID);

PROPERTY_DECLARE(CTest,LPSTR,Name);

};

REFLECT_IMPLEMENT(CTest);

PROPERTY_IMPLEMENT(CTest,int,ID);

PROPERTY_IMPLEMENT(CTest,LPSTR,Name);

实现:

void CTest::set_ID(int __value)

{

m_ID=__value;

}

int CTest::get_ID()

{

return m_ID;

}

void CTest::set_Name(LPSTR __value)

{

strcpy(m_Name,__value);

}

LPSTR CTest::get_Name()

{

return m_Name;

}

然后测试一下:

void main()

{

CTest t;

CPropertyInfo<CTest,int>* ID=FindProperty<CTest,int>("ID");

CPropertyInfo<CTest,LPSTR>* Name=PROPERTY(CTest,Name);

//修改属性

SET_PROP(&t,ID,1234);

SetProperty(&t,Name,(LPSTR)"hello");

//读取属性

cout<<GetProperty(&t,ID)<<endl<<GET_PROP(&t,Name)<<endl;

//枚举所有属性,和属性类型

CPropertyBase* Item;

for(Item=CTest::lpFirstProperty;Item;Item=Item->lpNext)

{

cout<<Item->szType<<" "<<Item->szName<<endl;

}

}

输出结果:

1234

hello

int ID

LPSTR Name

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有