用C++实现属性
发布时间:2011-3-29 20:18
发布者:1770309616
关键词:
属性
Delphi和C#的类都提供了“属性”的概念,使得Getter和Setter的方法可以像访问成员一样简单,如下面的Delphi代码: TMyClass = class private FValue: Integer; funcation GetValue: Integer; procedure SetValue(value: Integer); public property Value: Integer read GetValue write SetValue; end; 红色部分就是属性的声明,以后可以直接对Value进行读写,像下面这样: MyClass.Value := 100; v = MyClass.Value; 属性有几个显而易见的好处: •与Getter和Setter相比更加简单,就像直接访问成员一样。 •与直接访问成员相比,属性可以控制读写权限,并通过Getter和Setter对代码进行检验。 •属性对UI的所见即所得编辑很有用,可以很直观的设置某个属性,如大小,颜色等;QT似乎也大量应用属性,不过我没有去看过。 C++原生没有支持属性,但这个语言的特点就是语法强大,通过一些高级属性就可以实现其他语言的特性。要实现属性,C++当然是可以胜任了,而且实现方式有很多,我在网上就看过几种实现。不过在这里我要讲另外两种实现,一种是我想到的,另一种是编译器的扩展。 先看第一种,网上通常的实现是用“模板+操作符重载”的方式,这种方式需要在类的构造函数中初始化模板类成员,并且模板类包含了3个成员:外部类指针和读写函数指针。这个模板类成员就是“属性”,一个属性将浪费掉一些存储,如果一个类存在大量属性,则这个类的空间尺寸是可观的。 我的实现是用“本地类+操作符重载”的方式,用了3种本地类,分别实现“只读,只写,可读写”三种属性,用宏包装起来方便使用,请看下面的代码: // 取外部类实例指针(this) // outClass 外部类名 // localClassMem 本地类成员 #define OUTCLASS_THIS(outClass, localClassMem) ((outClass*)((unsigned char*)this - offsetof(outClass, localClassMem))) // 属性定义宏 // cls 定义属性的类 // type 属性的类型 // propname 属性名 // getter 读函数 // setter 写函数 #define PROPERTY_R(cls, type, propname, getter) \ class property_##getter \ { \ public: \ operator type () \ { \ return OUTCLASS_THIS(cls, propname)->getter(); \ } \ } propname #define PROPERTY_W(cls, type, propname, setter) \ class property_##setter \ { \ public: \ property_##setter &operator = (const type& value) \ { \ OUTCLASS_THIS(cls, propname)->setter(value); \ return *this; \ } \ } propname #define PROPERTY_RW(cls, type, propname, getter, setter) \ class property_##getter_##setter \ { \ public: \ operator type () \ { \ return OUTCLASS_THIS(cls, propname)->getter(); \ } \ property_##getter_##setter &operator = (const type& value) \ { \ OUTCLASS_THIS(cls, propname)->setter(value); \ return *this; \ } \ } propname 有了这几个宏,就可以写一个测试类来看看结果了: class Test { public: PROPERTY_R(Test, int, ValueR, GetValueR); PROPERTY_W(Test, float, ValueW, SetValueW); PROPERTY_RW(Test, bool, ValueRW, GetValueRW, SetValueRW); Test(): mValueR(100), mValueW(0), mValueRW(false) { } int GetValueR() { return mValueR; } void SetValueW(const float value) { mValueW = value; } bool GetValueRW() { return mValueRW; } void SetValueRW(bool value) { mValueRW = value; } private: int mValueR; float mValueW; bool mValueRW; };int _tmain(int argc, _TCHAR* argv[]) { Test test; int v = test.ValueR; cout< test.ValueRW = true; cout< 基本上可以满足要求了,内部类没有成员,一个类只占一个字节,比之前面的要节省得多。 尽管用标准语法可以实现“属性”,但仍有一些不足之处,首先是属性若传入有可变参数的函数时会有问题,如下面: printf("%d", test.ValueR); 编译器识别不出可变参数的具体类型,因此ValueR并没有默认转换为int,要这样写才正确: printf("%d", (int)test.ValueR); 另外一个问题是“数组属性”如何实现,至少我没有找到更好的办法,若哪位朋友有好的办法,不访分享出来。 如果你确定你的代码只会运行在Windows上,并且只用VC作为编译器,那么就可以用第二种实现。微软提供了property关键字用来支持属性机制,编译器会自动将属性替换为Get或Set函数,这样一来属性就根本不占用任何空间,也没有任何调用开销。 下面同样包装了几个宏,不仅实现了普通属性,也实现了数组类型的属性: #define PROPERTY_R(type, propname, getter) __declspec(property(get=getter)) type propname #define PROPERTY_W(type, propname, setter) __declspec(property(put=setter)) type propname #define PROPERTY_RW(type, propname, getter, setter) __declspec(property(get=getter, put=setter)) type propname #define PROPERTY_ARRAY_R(type, propname, getter) __declspec(property(get=getter)) type propname[] #define PROPERTY_ARRAY_W(type, propname, getter) __declspec(property(put=setter)) type propname[] #define PROPERTY_ARRAY_RW(type, propname, getter, setter) __declspec(property(get=getter, put=setter)) type propname[] 有了编译器的支持,事情的确简单得多了。 |
网友评论