一般来说,对于一个类而言,其状态的表达形式有很多,比如使用enum枚举
enum CLASS_STATUS{status1=0,status2,status3}
但假如这个类有多种状态,使用多个enum枚举状态值,效率往往没有按位计算来的更高。
假如有一个类,animal动物,有行动状态(飞,走,游),有身形状态(大,中,小),有颜色状态(红,白,蓝),我们可以这样设定:
#define animal_action_status_fly 0x00000001
#define animal_action_status_walk 0x00000002
#define animal_action_status_swim 0x00000004
#define animal_action_status_big 0x00000010
#define animal_action_status_medium 0x00000020
#define animal_action_status_small 0x00000040
#define animal_action_status_red 0x00000100
#define animal_action_status_white 0x00000200
#define animal_action_status_blue 0x00000400
当我们想表示一个中等身形的,会飞的蓝色动物,我们可以这样表示:
animal_action_status_medium | animal_action_status_fly | animal_action_status_blue
按位取或是对二进制而言的,所以这里的按位取或,是要将十六进制数值转换成二进制,从而计算。
十六进制的一位0~F转化成二进制为:0000~1111
而00、10、20、30~F0转化成二进制为:0000 0000~1111 0000
由此我们可以发现,如果进行如下计算
获取结合状态值
m_status = animal_action_status_medium | animal_action_status_fly
会得到
0x00000020 | 0x00000001
转化成二进制为
0010 0000 | 0000 0001
按位取或,结果为0010 0001,是两种状态结合的唯一二进制结果,
如若转化成十六进制,则为0x00000021,
既方便查看唯一状态值,又方便查验到底是哪几种状态的结合值。
设定的状态值,如果单一状态的数量在1~F(1~15个)时,每个状态占一位是可行的,但如果单一状态超过这个数值,就用两位表示一个状态即可。
比如,上面动物的例子,颜色状态不止有3个,有24个,如果第0个值该状态值表示为0x00000100,那么第24个的十六进制值表示为0x00001800
所以实际使用时,可根据实际情况,设计状态占的位数。
取消某个状态值
如
m_status &= ~ animal_action_status_fly
验证结合状态值
现在得到了一个结合后的状态值,如何知道这个animal都包含了哪些属性(状态)呢?
m_status=0x00000021
bool check(unsigned combinedStatus)
{
return (m_status & combinedStatus) !=0;
}
假如我想验证这个animal会不会走路walk,那么传入animal_action_status_walk进去,
计算 0x00000021 & 0x00000002 转为二进制计算为:
0010 0001 & 0000 0010 = 0000 0000 则函数返回false,即不包含walk状态。
假如我想验证这个animal身形是不是medium,那么传入animal_action_status_medium进去,
计算 0x00000021 & 0x00000020 转为二进制计算为:
0010 0001 & 0010 0000 = 0010 0000 则函数返回true,即包含medium状态。
需要注意的是
为了验证结合状态值,单个状态值的赋值,十六进制下只能是1、2、4、8、10、20、40、80……这样的数。
原因是,当用十六进制的一位表示一个状态值时,转换成二进制进行计算时,值为:
0x0001->0001
0x0002->0010
0x0004->0100
0x0008->1000
所以只能表达4个值,如果使用了这4个值以外的值,如0x0003->0011,
在验证结合状态值时,将会出现错误,比如这样定义
#define animal_action_status_climb 0x00000003
然后验证
m_status = animal_action_status_fly //0x00000001
0x00000003 & 0x00000001 转为二进制计算
0011 & 0001 = 0001 为非0数,则check函数返回true,代表m_status包含climb状态,而实际上他只有fly的状态。
所以为了验证时不出错,如果十六进制中每一位代表一个状态时,状态值只能写1、2、4、8,才能保证转化成二进制计算按位与时,不会出错。
这也就意味着,每种状态只允许4个值,当然可以扩展成两位十六进制来表示一个状态,比如1、2、4、8、10、20、40、80,这样就允许8个值了。
实际上这种方式的可玩性有各种各样,可以根据实际情况来声明和使用,以上只是给一个思路。