在C++实现C#中的属性(Property)功能的尝试: MACRO篇(2)
2007-08-29 22:59
696 查看
上文提到第一版有一些问题,于是要再这个基础上加以改进。回想C#中的属性的做法,实际上最终访问的是类的私有成员,如Length属性一般最终是访问的名为_length的私有成员,可以说是属性与成员的绑定。这种绑定初步设想可以用指针实现。
而自定义get/set函数,就让用户重写=操作符和自定义转换操作符就可以了。但是深入一想有一个大麻烦。自定义get/set函数的一个重要目的就是设置边界条件或者检查。如果这种检查不依赖对象的其它值(准确的说是非静态变量),问题还不大,但是实际中要依赖对象的其它值的情况也是相当普遍的,那么,就需要获得使用这个属性的对象指针。关于这个问题实在不好很完美的解决。
现在我的解决方案是使用一个基类存放使用属性的对象的指针,但是这样便涉及多处需要插入代码的局面。如果大家有更好的方法,欢迎和我交流。
第二版的宏定义如下:
#ifdef USE_PROPERTY
#define DECLARE_PROPERTY(ClassName) typedef ClassName HostClass;
class PropertyBase...{
public: inline static void SetPPOwner(HostClass* thispoint)...{PPOwner=thispoint;}
protected:
static HostClass* PPOwner;
};
#define BasicProperty(TYPE,NAME,REFObj) class TYPE##Property_##NAME :PropertyBase{
public:
inline TYPE operator=(TYPE value)...{PPOwner->REFObj=value;return value;}
inline operator TYPE()...{return PPOwner->REFObj;}
};
TYPE##Property_##NAME NAME;
//End of BasicProperty define.
#define ComplexProperty(TYPE,NAME) class TYPE##Property_##NAME :PropertyBase{
public:
TYPE operator=(TYPE ac);
operator TYPE();
};
TYPE##Property_##NAME NAME;
//End of ComplexProperty define.
//ComplexProperty should use Marco Setor and Getor to define its own get/set behavior
#define IMPLEMENT_PROPERTY(ClassName) typedef ClassName HostClass;
HostClass* HostClass::PropertyBase::PPOwner=NULL;
#define PROPERTYBASE_INIT PropertyBase::SetPPOwner(this);
#define Setor(TYPE,NAME) TYPE HostClass::TYPE##Property_##NAME::operator=(TYPE value)
#define Getor(TYPE,NAME) HostClass::TYPE##Property_##NAME::operator TYPE()
#define Property(TYPE,NAME,REFObj) BasicProperty(TYPE,NAME,REFObj)
#define CProperty(TYPE,NAME) ComplexProperty(TYPE,NAME)
#else
#define DECLARE_PROPERTY(ClassName)
#define IMPLEMENT_PROPERTY(ClassName)
#define BasicProperty(TYPE,NAME,REFObj)
#define ComplexProperty(TYPE,NAME)
#define PROPERTYBASE_INIT
#endif
要使用的话,首先要define USE_PROPERTY。然后在类的定义的开始部分插入一行DECLARE_PROPERTY(ClassName),在类的实现之前插入一行IMPLEMENT_PROPERTY(ClassName),并在类的所有构造函数中插入一行PROPERTYBASE_INIT。(大家应该看得出来我这是模仿的MFC的某些宏)
然后宏BasicProperty(TYPE,NAME,REFObj)是把类中的类型为TYPE,名为REFObj的成员绑定到属性NAME上。这个宏实现的是和第一版类似的功能,即缺省set/get功能。不同的是有了绑定,在类中直接访问REFObj就可以改变属性了。这个REFObj需要自己手工定义,当然,一般应是private或protected成员。
而宏ComplexProperty(TYPE,NAME)则是解决自定义set/get功能的宏。实现方法很简单,就是如上文所说重写=操作符和自定义转换操作符。使用这个宏以后,需要在类的实现文件中加入对应的宏Setor(TYPE,NAME)和Getor(TYPE,NAME),然后写出对应的函数体。(注意要加花括号)在函数中使用对象就使用PPOwner指针(即ProPertyOwner,属性所有者)。因为既然要自定义函数体,所以宏也就不用REFObj参数了,直接在函数体里使用对应的类成员即可。(至于用Setor和Getor这两个名字,主要是我本来想用Funtor实现的….-_-!)
注:稍候放出使用方法的实例程序。
回顾一下,手写Setor和Getor函数体是要达到的目的,所以没有增加复杂度;而关键是要使用PPOwner指针,以及它的初始化使得要在几处地方加代码。特别是需要在类的所有构造函数中添加PROPERTYBASE_INIT宏,显得很繁琐。
目前还没有加上只读只写功能,不过并不复杂,只需把BasicProperty宏定义和ComplexProperty宏定义中的=操作符和自定义转换操作符的声明改成用宏来声明就可以了。而这个宏默认当然是现在的语句不变,而需要实现比如只读,就把=操作符函数声明成private即可。这个就留给大家去完成吧。(这里同样可以参考MFC的做法。)
而自定义get/set函数,就让用户重写=操作符和自定义转换操作符就可以了。但是深入一想有一个大麻烦。自定义get/set函数的一个重要目的就是设置边界条件或者检查。如果这种检查不依赖对象的其它值(准确的说是非静态变量),问题还不大,但是实际中要依赖对象的其它值的情况也是相当普遍的,那么,就需要获得使用这个属性的对象指针。关于这个问题实在不好很完美的解决。
现在我的解决方案是使用一个基类存放使用属性的对象的指针,但是这样便涉及多处需要插入代码的局面。如果大家有更好的方法,欢迎和我交流。
第二版的宏定义如下:
#ifdef USE_PROPERTY
#define DECLARE_PROPERTY(ClassName) typedef ClassName HostClass;
class PropertyBase...{
public: inline static void SetPPOwner(HostClass* thispoint)...{PPOwner=thispoint;}
protected:
static HostClass* PPOwner;
};
#define BasicProperty(TYPE,NAME,REFObj) class TYPE##Property_##NAME :PropertyBase{
public:
inline TYPE operator=(TYPE value)...{PPOwner->REFObj=value;return value;}
inline operator TYPE()...{return PPOwner->REFObj;}
};
TYPE##Property_##NAME NAME;
//End of BasicProperty define.
#define ComplexProperty(TYPE,NAME) class TYPE##Property_##NAME :PropertyBase{
public:
TYPE operator=(TYPE ac);
operator TYPE();
};
TYPE##Property_##NAME NAME;
//End of ComplexProperty define.
//ComplexProperty should use Marco Setor and Getor to define its own get/set behavior
#define IMPLEMENT_PROPERTY(ClassName) typedef ClassName HostClass;
HostClass* HostClass::PropertyBase::PPOwner=NULL;
#define PROPERTYBASE_INIT PropertyBase::SetPPOwner(this);
#define Setor(TYPE,NAME) TYPE HostClass::TYPE##Property_##NAME::operator=(TYPE value)
#define Getor(TYPE,NAME) HostClass::TYPE##Property_##NAME::operator TYPE()
#define Property(TYPE,NAME,REFObj) BasicProperty(TYPE,NAME,REFObj)
#define CProperty(TYPE,NAME) ComplexProperty(TYPE,NAME)
#else
#define DECLARE_PROPERTY(ClassName)
#define IMPLEMENT_PROPERTY(ClassName)
#define BasicProperty(TYPE,NAME,REFObj)
#define ComplexProperty(TYPE,NAME)
#define PROPERTYBASE_INIT
#endif
要使用的话,首先要define USE_PROPERTY。然后在类的定义的开始部分插入一行DECLARE_PROPERTY(ClassName),在类的实现之前插入一行IMPLEMENT_PROPERTY(ClassName),并在类的所有构造函数中插入一行PROPERTYBASE_INIT。(大家应该看得出来我这是模仿的MFC的某些宏)
然后宏BasicProperty(TYPE,NAME,REFObj)是把类中的类型为TYPE,名为REFObj的成员绑定到属性NAME上。这个宏实现的是和第一版类似的功能,即缺省set/get功能。不同的是有了绑定,在类中直接访问REFObj就可以改变属性了。这个REFObj需要自己手工定义,当然,一般应是private或protected成员。
而宏ComplexProperty(TYPE,NAME)则是解决自定义set/get功能的宏。实现方法很简单,就是如上文所说重写=操作符和自定义转换操作符。使用这个宏以后,需要在类的实现文件中加入对应的宏Setor(TYPE,NAME)和Getor(TYPE,NAME),然后写出对应的函数体。(注意要加花括号)在函数中使用对象就使用PPOwner指针(即ProPertyOwner,属性所有者)。因为既然要自定义函数体,所以宏也就不用REFObj参数了,直接在函数体里使用对应的类成员即可。(至于用Setor和Getor这两个名字,主要是我本来想用Funtor实现的….-_-!)
注:稍候放出使用方法的实例程序。
回顾一下,手写Setor和Getor函数体是要达到的目的,所以没有增加复杂度;而关键是要使用PPOwner指针,以及它的初始化使得要在几处地方加代码。特别是需要在类的所有构造函数中添加PROPERTYBASE_INIT宏,显得很繁琐。
目前还没有加上只读只写功能,不过并不复杂,只需把BasicProperty宏定义和ComplexProperty宏定义中的=操作符和自定义转换操作符的声明改成用宏来声明就可以了。而这个宏默认当然是现在的语句不变,而需要实现比如只读,就把=操作符函数声明成private即可。这个就留给大家去完成吧。(这里同样可以参考MFC的做法。)
相关文章推荐
- 在C++实现C#中的属性(Property)功能的尝试: MACRO篇(1)
- c#中实现c/c++的__Line__和__FILE__功能
- C#中能实现同样功能的方法或属性的区别
- .Net/C# 实现真正的只读属性 (ReadOnly Property)
- Atitit java c# php c++ js跨语言调用matlab实现边缘检测等功能attilax总结
- .Net/C# 实现真正的只读的 Hashtable 类型的属性 (ReadOnly Hashtable Property)
- C++中实现C#属性相似的语法
- Atitit java c# php c++ js跨语言调用matlab实现边缘检测等功能attilax总结
- C也可以通过精心封装某些函数功能实现重用,那C++的类有什么优点吗(从面向对象的三大属性进行分析)
- 用C++实现类似C#属性
- 在C++中实现类似C#的字符串格式功能
- C++实现C#的get,set属性操作
- C#+AE 实现点击查询属性功能
- c++利用指针实现C#字典的功能
- c#控件实现类似c++中ocx控件功能,Event事件
- C#+AE 实现点击查询属性功能
- 在C++中实现“属性 (Property)”
- C# 能否实现像枚举一样自反射元数据属性的功能。
- C++中的property库的设计与实现过程(五)(第一部完)——为属性加入访问控制
- 在C++中实现“属性 (Property)”