C++中的属性

C++中的属性


 C#中有属性(Property),而C++中却没有,其实属性对于C++而言也是非常重要的,请往下看。


 什么是属性

 属性就像那些可以存储数据的变量,但在从它们中读写数据时会引发事件,换句话来说,属性就是一个有互作用的变量,自我更新,并在读写其自身时产生不同的值。
 使用像C#这样包含属性的语言非常容易编写一个类,但对C++来说似乎就不太可能了,因为C++的编译器不支持C#那种形式的属性。正因为此,本文就是要介绍如何编写带有像C#中属性的C++类。


 为什么属性很重要

 如果你需要编写一个代表人物的对象,这个对象可能包含以下数据:全名、年龄、出生年月、性别。如果用C++来编写,代码如下:


class Person {
public:
   Person( ){}
   virtual ~Person( ){}

private:    //数据成员

   char m_fName[20];
   char m_lName[20];

   UINT m_YearOfBirth;
   bool m_bGender;
};


 注意:在大多数情况中,不能为了可直接使用,就定义一个数据成员为public,因为数据成员应由对象内实现的业务逻辑来维护。

 如果需要设置或读取m_bGender的值,就可能要实现以下的方法:


class Person {
public:
   Person( ){}
   virtual ~Person( ){}

   void SetGender(bool bGender) {m_bGender = bGender;}
   bool GetGender() {return m_bGender;}

private:    //数据成员

   char m_fName[20];
   char m_lName[20];

   UINT m_YearOfBirth;
   bool m_bGender;
};


 这种方法的弊端在于必须要事先知道其名称与用途,要是使用属性,就简单多了,所需了解的只是属性名而已,且单个属性能支持不同的数据类型,也就是说,在上例中,可让Gender接受字符串或布尔类型,如下所示:


Person.Gender = "Male";

或:

Person.Gender = true;


 属性声明

 现在,来看如何编写属性,就从Gender属性开始吧:


class Person {
public:
   Person( ){}
   virtual ~Person( ){}

   Begin_Property(char*,Gender)
      __get(char*,Gender)
      _set(char*);

      _get(bool);
      _set(bool);

      __release(Gender)
   End_Property(Gender)

private:    //数据成员

   char m_fName[20];
   char m_lName[20];

   UINT m_YearOfBirth;
   bool m_bGender;
};


 代码中使用Begin_Property宏开始定义一个属性,它接受两个参数:属性数据类型及属性名。因为Gender属性是一个字符串属性,所以它应为char *。之后,还需要声明事件get()与set(),用于引发事件,如下所示:


// 这会引发 _set(bool) 事件
Person.Gender = true;
// 这会引发 _get(bool) 事件
bool gender = Person.Gender ;
// 这会引发 _set(char*) 事件
Person.Gender = "Male";
// 这会引发 _get(char*) 事件
printf("Gender :%s/n",(char*)Person.Gender);


 _get与_set是两个宏,分别接受一个参数,而这个参数代表了属性可接受的数据类型,你可看到_get与_set事件的数据类型独立于属性的数据类型,换句话来说,尽管Gender属性的数据类型为char *,但它也可接受布尔类型。
 最后两个宏为:_release,其释放它分配的内存;End_Property,其结束属性声明,两个宏都接受属性名为参数。


 属性的实现

 声明属性后,需要实现set()与get()了,请看如下的代码:


……
Begin_Property(char*,Gender)
   __get(char*,Gender)
   _set(char*)
   {
      //某些代码
      return Gender;
   }

   _get(bool)
   {
      //某些代码
      return iValue;
   }
   _set(bool)
   {
      //某些代码
      return iValue;
   }

   __release(Gender)
End_Property(Gender)
……


 在此可用实现宏来实现它,在讲述如何使用这些宏之前,先解释一下两点问题:__get宏是什么及为什么set()要返回一个值。在__get(char *)中,仅是返回一个指针:“return Gender”,它是默认的getter属性,因为“Gender”是一个char *属性,所以应这样使用它:“__get(char *,Gender)”。
 来看第二个问题,为什么set()要像get()那样返回一个值呢?简单来说,在C++中,set()能扮演get()的角色,请看下面的代码:


bool bGender = Person.Gender = true;


 现在,可使用Imp_set及Imp_get两个宏来实现Gender属性了,两个宏都接受三个参数:数据类型、类名及属性名,如下:


Imp_set(char*,Person,Gender)
{
   PROPERTY_PROLOGUE(Person,Gender)

   if (!Gender) Gender = new char[7];

   if (strlen(iValue)<6 )
   {
      int result;
      if ((result=strcmp(iValue,"Male"))==0)
         pThis->m_bGender = true;
      else
      {
         if ((result=strcmp(iValue,"Female"))==0)
         pThis->m_bGender = false;
      }

      if(result==0) strcpy(Gender,iValue);
   }
   return Gender;
}

Imp_set(bool,Person,Gender)
{
   PROPERTY_PROLOGUE(Person,Gender)

   if (!Gender) Gender = new char[7];

   if (pThis->m_bGender = iValue)
      strcpy(Gender,"Male");
   else
      strcpy(Gender,"Female");

   return (bool)iValue;
}

Imp_get(bool,Person,Gender)
{
   PROPERTY_PROLOGUE(Person,Gender)
   return pThis->m_bGender;
}


 因为set()与get()不能直接访问类成员,所以要使用PROPERTY_PROLOGUE宏,它定义了一个指向属性类的指针:“pThis”,如上所示。
 同时,在类的结尾处,需要释放内存及所有分配的资源,这由__release宏完成。__release是默认的释放宏,它的代码如下:


if (Gender)
{
   delete Gender;
   Gender = NULL;
}


 另外,也可使用_release及Imp_release来实现释放事件,如下所示:


Imp_release(Person,Gender)
{
   //在此释放所有分配的资源
}


 

         示例工程下载:Properties_Demo.zip

 

C++实现属性 本文译自http://www.codeguru.com/cpp_mfc/Property.html的Implementing 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到属性类property的set和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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值