分享
 
 
 

在C++中实现属性

王朝c/c++·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

本文由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 <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类实例。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有