XT中数据对象均从XItem继承而来,任何数据对象都有类型标识,身份ID,其中类型标识用于和其他对象区分,对外部访问而言,以字符串标识(通过静态函数ctypeString()访问,字符串长度应小于16),对于内部使用(运行时),则使用整数标识(在注册时动态生成,通过静态函数ctype()访问);整数身份ID(通过getId()访问),管理类通过身份ID构建对象的索引。
默认情况下,数据对象的整数标识按照注册顺序,从类型标识基数开始递增,类型标识基数与管理器的整数标识存在如下关系:
ItemTypeBase = DomainType*DomainItemTypeSize
其中DomainType为管理器整数标识,DomainItemTypeSize为每个管理器能容纳的对象类型的最大数目(现设为10000)。 开发者也可以为数据对象指定固定的整数标识,该整数标识须在(ItemTypeBase,ItemTypeBase+DomainItemTypeSize)区间。
下面是最简单的数据对象类声明和类实现:
//header
class XT_EXT_DOMAIN TestItem : public XItem
{
DECLARE_CITEM(TestItem)
public:
TestItem (ulong id);
~TestItem ();
}
//cpp
REGISTER_CITEM(TestItem, "CTESTITEM", TestManager::ctype(), 0);
TestItem::TestItem(ulong id)
:XItem(id,TestItem::ctype())
{
}
其中宏DECLARE_CITEM用于声明类型标识接口,宏REGISTER_CITEM用于实现类型标识接口,在对象构造函数中显示调用TestItem::ctype()以指定该对象的运行时类型,id一般由该对象的管理器自动分配。
宏REGISTER_CITEM的完整形式如下:
REGISTER_CITEM(ITEM, typeSTR, domainTYPE, typeID)
其中ITEM是数据类,typeSTR是类型字符串标识,typeID是整数标识,typeSTR不得与已注册的字符串重复并且字符串长度须小于16;domainTYPE为该数据对象所属的管理器的整数类型标识,必须在管理器注册后才能使用;当需要为ITEM自动获取类型ID时,将typeID设置为0即可,否则将按照typeID的值赋给ITEM。 一般的,类型字符串typeSTR格式可参考给定C[UserCode][DomainCode][ClassName],以大写字母C开头(Class),其中UserCode为3个字母的用户缩写码,在用户定制的场合使用,是可选项;DomainCode为3个字母的缩写域码,用于表示它所属的域类型,是可选项;ClassName是能表达数据对象类型的有意义的字符串,整体长度应小于16个字符,
对于带有名字的数据对象,可以从NItem继承实现。NItem提供了setName和getName的接口用于设置和获取数据对象的名字。数据对象的名字最长不得超过64个字符。
如果数据对象A至多属于一个数据对象B,则定义数据对象A和B具有从属关系。如几何面由三角片单元集组成,每一个三角片单元至多属于一个几何面。具有从属关系的数据对象来说,从对象在主对象中保持着顺序(一般是从对象加入主对象的顺序),从对象从OrderItem(当对象没有Name属性时)或者NOrderItem继承而来(当对象有Name属性时)。 当定义有从属关系的数据对象时,首先定义从对象:
class MasterItem;
class SlaveItem : public NOrderItem
{
private:
const MasterItem* m_pMaster;
DECLARE_CITEM(SlaveItem )
public:
SlaveItem (ulong id);
const MasterItem* getMaster() const { return m_pMaster; }
void setMaster(const MasterItem* master) { m_pMaster= master; }
};
然后,定义主对象,主对象中需要声明首尾从对象的指针,并且要实现attach和detach从对象的接口:
class MasterItem : public NItem
{
friend class SlaveManager;
const SlaveItem * m_pFront = 0, *m_pBack = 0;
ulong m_ulCount;
DECLARE_CITEM(MasterItem )
public:
MasterItem (ulong id) :NItem(id, MasterItem ::ctype()) { ; }
void attach(SlaveItem * pElement, SlaveManager* elMgr);
void detach(SlaveItem * pElement, SlaveManager* elMgr);
const SlaveItem * getFirstScene() const { return m_pFront; }
};
其中attach实现逻辑如下:
void MasterItem ::attach(SlaveItem* pElement, SlaveManager* elMgr)
{
assert(pElement->getMaster() != this);
if (m_pFront == NULL) {
m_pFront = pElement;
m_pBack = pElement;
pElement->setNext(NULL);
pElement->setPrev(NULL);
}
else {
elMgr->checkOutPrevNextItem(m_pBack)->setNext(pElement);
pElement->setNext(NULL);
pElement->setPrev(m_pBack);
m_pBack = pElement;
}
pElement->setMaster((MasterItem*)this);
++m_ulCount;
}