C++类成员属性的一种简洁实现

                  C++类成员属性的一种简洁实现

    一般来说对于标准C++而言是不存在成员属性这个概念的,以前大家都是用GetXXX/SetXXX来访问或取得数据,好象也没有感觉到任何不便。但是当我们用过C#之类的语言之后,我们总觉得C++这个方式太老土了。于是我们想去实现“属性”这个C++语言缺乏的要素。事实上网络上有很多人已经做了这部分工作,实现的方法有很多种,一种是用模板,一种是根据特定语言来写的,如VC(指的是Microsoft实现的C++)。但是它们要么很复杂,要么很难记住它的准确用法,嗯我总是喜欢简单的东西,因为太复杂的东东会让我的头脑当机。废话少说,来看看如何实现。
在实现之前,我必需先探讨一下为什么需要“属性”这个东东。比如说下面雇员这个类:

    1. class CEmployee
    2. {
    3. public:
    4.   int Old; //年龄
    5. };
    6. CEmployee employee;
    7. employee.Old=22;
    8. int old =employee.Old;

    它有一个成员变量,我们可以直接对它们进行赋值或者读取,但是往往会缺少一个很重要的东东,就是不能对所赋值进行校验,这可是个大问题,比如我们给Old一个负值,比如-50,程序运行时不会有任何错误,但是的确这个成员变量的值在逻辑上是不正确的。于是我们会写上GetOld、SetOld。现在OK了,这个小问题解决了,但新问题来了。我们的类使用者,他们需要重新把他们的代码成写如下的样子,而不是上面的那样。
    1.   CEmployee employee;
    2.   employee.SetOld(22);
    3.   int old =employee.GetOld();

    你的伙伴一定会在写代码时诅咒你写了一个垃圾的类。所以你决定要改变这个现状。很幸运,你是MS的忠实用户,而且你对于MSDN看很仔细,所以你知道可以这样来写
    1. class CEmployee
    2. {
    3. private:
    4.   int m_old;
    5. public:
    6.  _declspec(property(get= GetOld,put=SetOld))int Old;
    7.  
    8.  int GetOld(void)
    9.  {
    10.   return m_old;
    11.  }
    12.  void SetOld(int value)
    13.  {
    14.   if( (value >0) && (value <60))
    15.   {
    16.   m_old = value;
    17.   }
    18.   else
    19.   {
    20.   m_old =20;
    21.   }
    22.  }
    23. };

    Very Good,上面的类完美地完成一个属性所要做的目标,不过还有一点小问题,象我这样比较笨的经常需要查找MSDN才会知道   
    1. _declspec(property(get= GetOld,put=SetOld))int Old;
    这句话的含义,而且我也经常忘记它的具体写法,比如put我常把它写成了set,这总是让我想起了使用C#的美好时光,它是可以写成这个样子的

    1. public class CEmployee
    2.  {
    3.   private int m_old;
    4.   public int Old
    5.   {
    6.   get
    7.   { return m_old; }
    8.   set
    9.   {
    10.     if(value >0 && value <60)
    11.     {
    12.         m_old = value;
    13.      }
    14.     else
    15.     {
    16.         m_old =20;
    17.      }
    18.   }
    19.   }
    20.  }

所以我想到可以利用C/C++中强大的武器宏,我们来定义几个宏

    1. #define PROP(T,X) __declspec(property(get= __get##X,put= __put##X))T X;
    2. #define GETPROP(T,X) __declspec(property(get= __get##X))T X; //只读属性
    3. #define SETPROP(T,X) __declspec(property(put= __put##X))T X; //只写属必
    4. #define GET(T,X) T __get##X(void) 
    5. #define SET(T,X) void __put##X(T value)

    说明一下:T 代表属性的类型如int,double,CString,而X代表属性名称。如果你需要一个只读属性可以使用GETPROP,只写属性则可以使用SETPORP,然后对应使用一个GET或SET,当然如果你用PROP,而只用了一个GET或SET,也没有错,只是在编译时会告诉你没有一个__getXXX或__putXXX的方法。然后我们就可以这样来写我们的类。

    1. class CEmployee
    2. {
    3. private:
    4.   int m_old;
    5. public:
    6.  PROP(int ,Old)
    7.  GET(int,Old)
    8.  {
    9.   return m_old;
    10.  }
    11.  SET(int,Old)
    12.  {
    13.   if( (value >0) && (value <60)) //这里的value你可把它和C#一样当做关键字
    14.   {
    15.   m_old = value;
    16.   }
    17.   else
    18.   {
    19.   m_old =20;
    20.   }
    21.  }
    22. };

    好了,我们要做的工作已经做完了。当然这种方法还是有很多问题,比如不能使用C#中常用的索引属性,静态属性等等。但是毕竟我们是C++程序员么,呵呵!最后,这种方法只是在VC下有用。


C++实现属性 本文译自http://www.codeguru.com/cpp_mfc/Property.htmlImplementing a Property in C++ 以下是译文 本文由Emad Barsoum投稿。 开发测试环境:Visual C++ 7.0, Windows XP sp1, Windows 2000 sp3 摘要 本文试着在C++中不使用任何扩展技术模拟C#(或其他语言)中属性特征。大多数在C++实现属性库和编译器使用扩展技术,如Managed C++C++ Builder,或者他们使用如通常函数set和get方法,但那不是属性。 详述 我们首先看一下什么是属性。一个属性表现为一个字段或者成员变量,但它通过read和write方法或者get和set方法暗中操作变量。 例如,若存在A和它属性Count,我可以写如下代码: A foo; Cout << foo.Count; 实际上Count调用它get函数返回当前变量值。你可以将属性定为只读(你可以读取它但不能修改它)、只写或者可读写,这就是使用属性而不直接使用变量一个最大好处了。好了,让我们开始来实现它: 我们需要能做如下事: int i = foo.Count; //--调用get函数得到值 foo.Count = i; //-- 调用set函数设定值 因此,很明显我们需要重载 = 操作符使其能设定变量值,同时也要重载该属性返回值(在下面我们将会看到)。 我们将实现一个称为property,它做就像一个属性,声明如下: template class property {} 这个模板表示是我们属性。Container是我们要在其中包含属性变量,set和get方法以及属性型。ValueType是内部变量即要定义属性型,nPropType定义属性读写标志:只读、只写或可读写。 现在我们需要一个指向从包含属性Container到属性propertyset和get方法指针,同时重载 = 操作符以使得属性能象变量起那样作用。现在我们来看property全部定义 #define READ_ONLY 1 #define WRITE_ONLY 2 #define READ_WRITE 3 template class property { public: property() { m_cObject = NULL; Set = NULL; Get = NULL; } //-- 将m_cObject指向包含属性container -- void setContainer(Container* cObject) { m_cObject = cObject; } //-- 设定可改变属性set成员函数 -- void setter(void (Container::*pSet)(ValueType value)) { if((nPropType == WRITE_ONLY) || (nPropType == READ_WRITE)) Set = pSet; else Set = NULL; } //-- 设定可检索属性get成员函数 -- void getter(ValueType (Container::*pGet)()) { if((nPropType == READ_ONLY) || (nPropType == READ_WRITE)) Get = pGet; else Get = NULL; } //-- 重载 = 号操作符使其能用set成员设定属性值-- ValueType operator =(const ValueType& value) { assert(m_cObject != NULL); assert(Set != NULL); (m_cObject->*Set)(value); return value; } //-- 使属性能转换为内部型成为可能-- operator ValueType() { assert(m_cObject != NULL); assert(Get != NULL);
评论 2 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

BlueDog

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值