在C++中实现属性
2008-03-08 12:53:57 来源:WEB开发网核心提示: 详述 我们首先看一下什么是属性,一个属性表现为一个字段或者成员变量,在C++中实现属性,但它通过read和write方法或者get和set方法暗中操作变量, 例如,当然,直接使用set和get函数效率 要更高些,若存在类A和它的属性Count,我可以写如下的代码: A
详述
我们首先看一下什么是属性。一个属性表现为一个字段或者成员变量,但它通过read和write方法或者get和set方法暗中操作变量。 例如,若存在类A和它的属性Count,我可以写如下的代码: A foo; Cout << foo.Count; 实际上Count调用它的get函数返回当前的变量值。你可以将属性定为只读(你可以读取它但不能修改它)、只写或者可读写,这就是使用属性而不直接使用变量的的一个最大好处了。好了,让我们开始来实现它: 我们需要能做如下的事: int i = foo.Count; //--调用get函数得到值 foo.Count = i; //-- 调用set函数设定值 因此,很明显的我们需要重载''=''操作符使其能设定变量的值,同时也要重载该属性的返回值(在下面我们将会看到的)。 我们将实现一个称为property的类,它做的就像一个属性,声明如下: template <typename Container, typename ValueType, int nPropType> 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 <typename Container, typename ValueType, int nPropType> 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); return (m_cObject->*Get)(); } private: Container* m_cObject; //-- 指向包含属性的类模块 -- void (Container::*Set)(ValueType value); //-- 指向set成员函数的函数指针 -- ValueType (Container::*Get)(); //-- 指向get成员函数的函数指针 -- }; 现在让我们来一段一段地看这些代码:
在下面的代码中,仅仅将Container指针指向一个有效的包含属性的实例。void setContainer(Container* cObject) { m_cObject = cObject; }下面的代码,设定指针指向包含属性的类中的set和get成员函数,其set和get成员函数度有,唯一的限制即set成员函数必须有一个ValueType型的参数并无返回值,get成员函数没有参数,但要返回ValueType型值。 //-- 设定可改变属性值的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类型一样起作用,所以它返回包含属性的类中get函数的返回值。 //-- 重载''=''号操作符使其能用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); return (m_cObject->*Get)(); }
现在我们来看看怎样使用它:
如下所示,在PropTest类中定义了一个叫做Count的简单属性。Count的实际值将保存到或检索之在PropTest的私有成员变量"m_nCount"中,通过PropTest的get和set方法。get和set方法可以使用任何的变量名字,只需他们的地址能被传递到property类中,如下面的PropTest构造函数里面的代码般,代码行" property<PropTest, int, READ_WRITE> Count; "让我们在PropTest中得到可读写的int型的Count属性。现在你可以使用如一般的成员变量般使用使用Count属性了,但实际上你是间接地调用它set和get方法。
要使Count属性能成功工作,必须先在PropTest的构造函数里面对其进行初始化。 class PropTest { public: PropTest() { Count.setContainer(this); Count.setter(&PropTest::setCount); Count.getter(&PropTest::getCount); } int getCount() { return m_nCount; } void setCount(int nCount) { m_nCount = nCount; } property<PropTest,int,READ_WRITE> Count; private: int m_nCount; };如下所示,你可以象使用普通变量一样使用Count属性。 int i = 5,j; PropTest test; test.Count = i; //-- 调用set函数 -- j= test.Count; //-- 调用get函数 -- 要使用只读的属性,你可以创建如下的property实例:property<PropTest,int,READ_ONLY > Count; 要使用只写的属性,你可以创建如下的property实例: property<PropTest,int,WRITE_ONLY > Count; 注重:假如你将某一属性设为只读,当你对其赋值时,将引发assertion诊断。同理,当读取只写的属性时
也同样会引发assertion诊断。
小结
本文展示了在C++只用标准的C++特性而不使用其他任何的扩展技术来实现属性。当然,直接使用set和get函数效率
要更高些,因为本文中的方法需要为每一个属性定义一个property类实例。
我们首先看一下什么是属性。一个属性表现为一个字段或者成员变量,但它通过read和write方法或者get和set方法暗中操作变量。 例如,若存在类A和它的属性Count,我可以写如下的代码: A foo; Cout << foo.Count; 实际上Count调用它的get函数返回当前的变量值。你可以将属性定为只读(你可以读取它但不能修改它)、只写或者可读写,这就是使用属性而不直接使用变量的的一个最大好处了。好了,让我们开始来实现它: 我们需要能做如下的事: int i = foo.Count; //--调用get函数得到值 foo.Count = i; //-- 调用set函数设定值 因此,很明显的我们需要重载''=''操作符使其能设定变量的值,同时也要重载该属性的返回值(在下面我们将会看到的)。 我们将实现一个称为property的类,它做的就像一个属性,声明如下: template <typename Container, typename ValueType, int nPropType> 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 <typename Container, typename ValueType, int nPropType> 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); return (m_cObject->*Get)(); } private: Container* m_cObject; //-- 指向包含属性的类模块 -- void (Container::*Set)(ValueType value); //-- 指向set成员函数的函数指针 -- ValueType (Container::*Get)(); //-- 指向get成员函数的函数指针 -- }; 现在让我们来一段一段地看这些代码:
在下面的代码中,仅仅将Container指针指向一个有效的包含属性的实例。void setContainer(Container* cObject) { m_cObject = cObject; }下面的代码,设定指针指向包含属性的类中的set和get成员函数,其set和get成员函数度有,唯一的限制即set成员函数必须有一个ValueType型的参数并无返回值,get成员函数没有参数,但要返回ValueType型值。 //-- 设定可改变属性值的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类型一样起作用,所以它返回包含属性的类中get函数的返回值。 //-- 重载''=''号操作符使其能用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); return (m_cObject->*Get)(); }
现在我们来看看怎样使用它:
如下所示,在PropTest类中定义了一个叫做Count的简单属性。Count的实际值将保存到或检索之在PropTest的私有成员变量"m_nCount"中,通过PropTest的get和set方法。get和set方法可以使用任何的变量名字,只需他们的地址能被传递到property类中,如下面的PropTest构造函数里面的代码般,代码行" property<PropTest, int, READ_WRITE> Count; "让我们在PropTest中得到可读写的int型的Count属性。现在你可以使用如一般的成员变量般使用使用Count属性了,但实际上你是间接地调用它set和get方法。
要使Count属性能成功工作,必须先在PropTest的构造函数里面对其进行初始化。 class PropTest { public: PropTest() { Count.setContainer(this); Count.setter(&PropTest::setCount); Count.getter(&PropTest::getCount); } int getCount() { return m_nCount; } void setCount(int nCount) { m_nCount = nCount; } property<PropTest,int,READ_WRITE> Count; private: int m_nCount; };如下所示,你可以象使用普通变量一样使用Count属性。 int i = 5,j; PropTest test; test.Count = i; //-- 调用set函数 -- j= test.Count; //-- 调用get函数 -- 要使用只读的属性,你可以创建如下的property实例:property<PropTest,int,READ_ONLY > Count; 要使用只写的属性,你可以创建如下的property实例: property<PropTest,int,WRITE_ONLY > Count; 注重:假如你将某一属性设为只读,当你对其赋值时,将引发assertion诊断。同理,当读取只写的属性时
也同样会引发assertion诊断。
小结
本文展示了在C++只用标准的C++特性而不使用其他任何的扩展技术来实现属性。当然,直接使用set和get函数效率
要更高些,因为本文中的方法需要为每一个属性定义一个property类实例。
更多精彩
赞助商链接