用C++实现属性

原创 2010年11月21日 01:02:00

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++类成员属性的一种简洁实现    一般来说对于标准C++而言是不存在成员属性这个概念的,以前大家都是用GetXXX/SetXXX来访问或取得数据,好象也没有感觉...
  • BlueDog
  • BlueDog
  • 2008年12月14日 23:58
  • 6383

C++的属性指示符

C++的属性指示符,有点类似Java中Anotation, 是可以实现定义的。它主要是用来引入一些对象,类型,代码的属性,也可以理解为限制对象,类型,代码的一些行为。它为实现定义的语言扩展提供标准统一...
  • duandianR
  • duandianR
  • 2017年05月27日 22:00
  • 928

C++中的属性

C++中的属性 C#中有属性(Property),而C++中却没有,其实属性对于C++而言也是非常重要的,请往下看。 什么是属性 属性就像那些可以存储数据的变量,但在从它们中读写数据时会引发事件,换句...
  • xieqidong
  • xieqidong
  • 2008年11月10日 09:10
  • 7614

C++的string与属性封装

string#include #include #include using namespace std; int main(void) { string name; cout
  • liuzp111
  • liuzp111
  • 2016年12月26日 22:56
  • 410

C++ 访问属性

对于类的继承,有public,protect,priavte.public 不用说。 private:类中成员是此属性,则表明这个成员只属于此类,只有此类里面的成员函数可以操作,其他任何情况都不允许...
  • wang664626482
  • wang664626482
  • 2016年04月01日 11:42
  • 358

为C++的类添加属性和事件

为C++的类添加属性和事件在Visual Basic中,一个类具有属性、方法和事件等几个特征,而C++中的类只提供方法,使用时稍显麻烦。本文的目的就是在C++的类中模拟实现属性和事件。 (C)ShiS...
  • shishengsoft
  • shishengsoft
  • 2007年09月09日 20:01
  • 3965

C++ 使用 property 属性 的方法

这几天在项目中碰到一个问题: A是顶层的对象,有一个成员变量是系统参数p。 B是A对象的成员的成员,B负责通信。B在通信时,会使用到参数p。第一个最直接的方案是:将A对象p的指针直接传递给B。 ...
  • spark550
  • spark550
  • 2016年11月25日 17:40
  • 902

在C++中实现“属性 (Property)”

在C++中实现“属性 (Property)” 摘要:本文介绍了在C++中实现“属性 (Property)”的方法,“属性”是我们在C#(或其它一些语言)中常常能用到的一种特性。这里介绍的实现方法使用的...
  • lifanxi
  • lifanxi
  • 2003年05月12日 18:18
  • 2025

C++中使用属性(property)

在C++中也可以使用像C#中的属性。在某些特定的环境我们可以使用这一方法,虽然在效率上会比直接访问要来得慢。但是这点效率基本可以忽略的。。代码大致如下: #include using namespac...
  • masefee
  • masefee
  • 2009年03月25日 12:23
  • 4679

给C++添加属性机制

    以前用DELPHI和C#时,对DELPHI和C#语法中的属性感到十分方便,在读写属性时能自动调用属性的get, set函数或代码.但我最喜欢的C++中没有属性机制.不过C++提供了范型编程和操...
  • pankun
  • pankun
  • 2006年02月08日 13:03
  • 3687
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:用C++实现属性
举报原因:
原因补充:

(最多只允许输入30个字)