`
javasogo
  • 浏览: 1766060 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

用C++实现属性

阅读更多

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<<v<<endl;
test.ValueW = 1.0f;
test.ValueRW = true;
cout<<test.ValueRW<<endl;

return 0;
}
基本上可以满足要求了,内部类没有成员,一个类只占一个字节,比之前面的要节省得多。
尽管用标准语法可以实现“属性”,但仍有一些不足之处,首先是属性若传入有可变参数的函数时会有问题,如下面:
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[]
有了编译器的支持,事情的确简单得多了。
分享到:
评论

相关推荐

    在c++中实现属性

    大多数在C++实现属性的库和编译器使用扩展技术,如Managed C++或C++ Builder,或者他们使用如通常函数的set和get方法,但那不是属性。 详述 我们首先看一下什么是属性。一个属性表现为一个字段或者成员变量,但它...

    c++实现反射demo

    用c++实现了反射

    C++实现属性表单和向导生成

    简单演示了属性表单的建立方法以及向导的生成

    粗糙集属性约简 C++实现

    粗糙集属性约简 C++实现,对各个函数进行封装,共有四个类,希望大家进行改进

    C++实现数据库DBMS建表插入删除属性功能

    C++实现数据库DBMS建表插入删除属性功能

    C++实现小型数据库DBMS,具备建表以及属性插入功能

    C++实现小型数据库DBMS,具备建表以及属性插入功能。

    C++实现SVM分类算法

    SVM有如下特征:(1)SVM学习问题可以表示为凸优化问题,因此可以利用已知的有效算法发现目标函数...本代码通过C++实现SVM的分类算法,并通过SSE实现最优解的快速计算,学习SVM的同学可以参考一下,如有不足,请指正。

    编译原理三地址代码生成C++实现

    这是一个关于C语言的一个编译器设计的一部分,生成了三地址中间代码,C++实现。应该是不错的,您下了不后悔。

    C++builder 实现动态添加按钮以及随意拖动实现

    本程序是在C++builder中实现动态添加Button组件,其中Button属性可更改成其他任何的其他组件。代码我本人编写,浅显易懂,在此分享一下。

    C++反射机制实现

    C++反射机制实现,根据类名字符串创建该类的实例;根据类的属性字符串来设置属性;

    QML 与 C++交互 - 01QML访问C++属性

    本系列会介绍几种QML与C++进行数据交互的方法,包括信号槽的链接,QML调用C++类的方法等。 本文为第一篇:QML访问C++属性。可以访问我的博客查看代码解释。

    背单词软件C++实现

    背单词软件C++实现 整体考虑程序应该实现的功能,有单词选意、中文选词、选词填空、全拼练习和退出程序一共5个功能。 首先建立一个主窗体,在窗体上增加五个按钮控件,其Text属性分别为英文选意、中文选词、选词填空...

    程序设计作业: p2p聊天系统 qt写的界面 C++实现.zip

    Qt是一个用标准C++编写的跨平台开发类库,它对标准C++进行了扩展,引入了元对象系统、信号与槽、属性等特性,使应用程序的开发变得更高效。 Qt类库中大量的类以模块形式分类组织的,包括基本模块和扩展模块等。一个...

    关联,聚合,组合的区别及C++实现

    在类图中,除了需要描述单独的类的名称、属性和操作外,我们还需要描述类之间的联系,因为没有类是单独存在的,它们通常需要和别的类协作,创造比单 独工作更大的语义。

    duilib原生库,派生Lable控件,C++实现文字跑马灯 滚动显示的效果

    duilib原生库,派生Lable控件,C++实现文字跑马灯 滚动显示的效果。 派生出来的lable控件,具有以下功能: 1. 基类 Lable的所有基本功能 2. 当设置的文字不为空时,自动跑马灯 滚动显示文字,显示速度由外部 xml ...

    C++实现员工管理系统.zip

    利用文件处理方式实现对公司人员(包括销售员、经理和销售经理)进行管理,具有增加数据、更新数据、查询数据、删除数据以及重组文件的功能。(删除数据在记录中做删除标志,重组文件指在物理上删除有删除标志的记录...

    C/C++实现控制台输出不同颜色字体的方法

    主要介绍了C/C++实现控制台输出不同颜色字体的方法,涉及C++控制台文字属性相关设置操作技巧,需要的朋友可以参考下

    一个c++实现的哈希表类

    程序的具体实现如下:本程序是用模板类myhash来实现,包括protected和public属性成员。其中protected成员有*ht(自定义散列表指针)、*empty(bool类型指针,功能是将元素值空、m(散列表容量)、p(除留余数法的除数)...

    编写C++程序用类与对象的思想求一个有关矩阵的算法

    编写C++程序完成以下功能: (1) 定义一个Point类,其属性包括点的坐标,提供计算两点之间距离的方法; (2) 定义一个矩形类,其属性包括左上角和右下角两个点,提供计算面积的方法; (3) 创建一个矩形对象,...

    VC基于对话框的属性页实现工程

    VC基于对话框的属性页实现工程,每个属性页可放置独立的控件

Global site tag (gtag.js) - Google Analytics