CArray数组对象序列化问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CArray数组对象序列化问题相关的知识,希望对你有一定的参考价值。
我在文档中定义了:
public:
int amount;//记录数组长度
CArray<myclass,myclass*>amyclass;
然后在文档中序列化如下:
......
ar>>amount;//记录数组长度;
ar>>amyclass;
........
我想用amount来数组初始化:即调用amyclass.Setsize(amount);有必要吗?如有必要,如何才能做到。
void CASTasks::Serialize(CArchive& ar)
CObject::Serialize(ar);
if(ar.IsStoring())
ar<<m_taskNum;//数组元素个数
for(int i=0; i<m_tasks.GetSize(); i++)
m_tasks[i].Serialize(ar);//序列化每个元素
else
ar>>m_taskNum;
m_tasks.RemoveAll();//重建数组
for(int i=0; i<m_taskNum; i++)
CASTask task;
m_tasks.Add(task);
m_tasks[i].Serialize(ar);//反序列化出来
m_taskNum跟你定义的amount是一个意思, m_tasks 定义为 CArray <CASTask, CASTask&> m_tasks; 参考技术B 用不着这么复杂!
C++创建了一个panel,如何在里面输出
参考技术A 1.CArrayVS::std::vector?CArray和::std::vector一样,都是模板类,用于管理任意类型的对象的动态数组。都在解构时释放所管理的动态内存。因此都可以用于代替手工动态数组管理。但是,CArray是在C++标准化之前很多年(VC++2.0时代)设计的,当时对C++程序设计,面向对象程序设计,模板程序设计等技术认识严重不足,尤其是当时对面向对象技术的错误信仰与宣传,造成CArray的设计有重大错误。在C++语言标准化以后(1998),以及VC++6.0出世以后,提供了标准的::std::vector模板,基本上在任何方面都要优于CArray。Microsoft由于要支持老的程序,因此一直保留了CArray,但显然并没有打算按照新的思想去发展它(至少应该提供operator=(CArrayconst&)吧)。概括起来,CArray与::std::vector有以下不同:1)CArray是MFC中的,::std::vector存在于任何标准的C++实现中。因此,你用熟了CArray也只能在MFC中用,若用熟了::std::vector,你可以在任何平台的任何C++编译器下使用。使用标准的部件也有利于别人理解你的程序。.CArray继承了CObject,仅仅为了实现serialization,这是不恰当的,违反了"Youdon'tpayforwhatyoudon'tuse."的C++设计原则。::std::vector没有继承任何东西,只是实现了管理一个动态数组该做的事。2)CArray不是一个恰当的值类型,例如下列操作都是不合法的:CArraya;CArrayb(a); //error,mustuseCopy().b=a; //error,mustuseCopy().b==a; //error,youmustwriteyourown.b相反,::std::vector是一个认真设计的值类型,天生是可以拷贝构造和可赋值的。如果T是可比较的,那么::std::vector将自动地是可以比较的。此外,由于涉及到四个特殊成员函数;T();//缺省构造函数(defaultconstructor)~T();//解构函数(destructor)T(Tconst&);//拷贝构造函数T&operator=(Tconst&);//拷贝赋值函数的自动生成,如果使用CArray()作为T的成员变量,那么上述的四个特殊函数中的后两个将无法自动生成,需要手工写:structT T() T(Tconst&t) a_.Copy(t.a_); i_=t.i_; d_=t.d_; s_=t.s_; T&operator=(Tconst&t) if(this!=&t) a_.Copy(t.a_); i_=t.i_; d_=t.d_; s_=t.s_; return*this; private: CArraya_; inti_; doubled_; ::std::strings_;;如果使用::std::vector:structTprivate: ::std::vectora_; inti_; doubled_; ::std::strings_;;上面列出的三个特殊成员函数都不需要写。好处是明显的:当你增减T的成员变量时,你不必到T(Tconst&)和operator=()中去相应地增减。3)没有现成的算法可以对CArray进行操作,而标准C++里的标准算法大多都可以直接在::std::vector上运行。例如:staticintconstinit_vals[]=3,1,4,1,6,9;vectora(init_vals,init_vals+6);*find(a.begin(),a.end(),6)=5; //把6改成5sort(a.begin(),a.end()); //排序。可以说,CArray的主要设计错误是把一个本来应该是一个简单的“值”类型的东西设计成一个难用的“对象”类型了。所有的“值”的好特性都丧失了,但那些从CArray继承的派生类呢?CByteArray等的问题与CArray的问题一样,甚至(例如,CPtrArray,永远不要用)。同样,其他的MFCcontainer模板,象CMap,CList等,都有类似问题,都应该用::std::map,::std::list等设计更好的东西代替。2.::std::vector在哪里?::std::vector在头文件中定义:(注意,标准的C++头文件都没有.h后缀,有.h的文件是与C兼容的,或支持老的不标准的东西,象。)namespacestd template> structvector //具体内容稍后讨论 ; template booloperator==(vectorconst&a,vectorconst& b); template booloperator!=(vectorconst&a,vectorconst& b); template booloperatorconst&a,vectorconst& b); template booloperator>=(vectorconst&a,vectorconst& b); template booloperator>(vectorconst&a,vectorconst& b); template booloperator>=(vectorconst&a,vectorconst& b);vector定义在namespacestd中,使用时为了减少击键次数,通常使用一个类型定义缩短类型名称:#includetypedef::std::vectorIntVector;IntVectora;IntVectorb(a);IntVectorc;c=b;assert(a==c);请注意中定义了六个vector的比较函数。这些函数只在真的用到时才会被实例化,才会要求T也提供operator==()和operator:用于提供一个用户定义的存储管理类。由于这个参数很少用到,而且在VC++6的实现中有问题,不能用,因此以下的讨论忽略这一部分的内容。3.::std::vector中的类型定义vector中定义了一些类型,下面只列出常用的:typedefTvalue_type;typedefT0iterator;typedefT1const_iterator;typedefT2reverse_iterator;typedefT3const_reverse_iterator;value_type就是vector的元素类型,也就是T。当写通用的算法处理任意类型的vector或其他容器类型时是很有用的。iterator/const_iterator是两个vector的实现定义的未知类型,用于访问vector中的元素,类似于T*/Tconst*指针,他们的区别是一个指向的元素可被修改,另一个只可以读:typedef::std::vectorIntVector;IntVector::iteratoriter;IntVector::const_iteratorc_iter;//++iter;iter++;//ok:increment,post-increment.--iter;iter--;//ok:decrement,post-decrement.++c_iter;c_iter++;//ok:increment,post-increment.--c_iter;c_iter--;//ok:decrement,post-decrement.*iter=123;//ok.intk=*iter;//ok.k=*--c_iter;//ok.*c_iter=k;//error.c_iter=iter;//ok:iteratorisconvertibletoconst_iterator.iter=c_iter;//error:can'tconvertconst_iteratortoiterator.在使用上iterator/const_iterator和T*/Tconst*基本相同,事实上有些vector的实现里就是用T*/Tconst*实现iterator/const_iterator的,但又不可以把iterator/const_iterator当作真正的T*/Tconst*:T*p=iter;//mayfailtocompile.Tconst*q=c_iter;//mayfailtocompile.reverse_iterator/const_reverse_iterator与iterator/const_iterator类似,但以相反的次序(从尾至头)访问vector中的元素。各种各样的iterator在STL中有特别重要的意义,但这里我们不做具体介绍。只要理解通过iterator可以访问vector中的元素,大概相当于一个指示位置的指针就行了。4.::std::vector的构造vector提供了以下构造函数:(忽略allocator参数)vector();vector(size_tn,Tconstt=T());vector(vectorconst&);vector(const_iteratorfirst,const_iteratorlast);1)vector();构造一个空的vector,不包含任何元素。IntVectorv1;//空的整数向量。2)vector(size_tn,Tconstt=T());构造一个n个相同元素t组成的vector。如果不给出t,那么将用T()做缺省值:IntVectorv2(100,1234);//100个1234.IntVectorv3(100);//100个0。3)vector(vectorconst&other);复制构造函数,复制other中的内容:IntVectorv4(v2);//100个1234。4)vector(const_iteratorfirst,const_iteratorlast);事实上,这个构造函数应该为template vector(Iterfirst,Iterlast);即拷贝任意的序列[first,last)到vector中。由于VC++6sp0编译程序的限制,Iter被换为const_iterator了。不过,碰巧const_iterator就是Tconst*,所以可以如下使用:inta[]=1,2,3,4,5;IntVectorv5(a,a+5);//1,2,3,4,5IntVectorv6(v5.begin()+2,v5.end());//3,4,55.访问vector中的元素以下成员函数/运算符用于访问vector中的一个元素:T&at(size_tn);Tconst&at(size_tn)const;T&operator[](size_tn);Tconst&operator[](size_tn)const;T&front();Tconst&front()const;T&back();Tconst&back()const;请注意,由于vector是一个“值”语义的对象,所有的操作函数都必须严格保证const的正确性。所以,所有的元素访问方法都有const和非const两个版本。at(n)和operator[](n)都返回下标为n的元素的引用,他们的区别是,at()进行下标越界检查,若发现越界,抛出range_error异常,operator[]不进行下标检查。front()返回下标为0的元素的引用,back()返回最后一个元素的引用。inta[]=4,1,4,1,5,8;IntVectorv(a,a+6);//使用front(),back():v.front()=3;v.back()=9;//使用operator[]():for(size_ti=0;i的存储管理以下成员函数用于存储管理:voidreserve(size_tn);size_tcapacity()const;voidresize(size_tn,Tt=T());voidclear();size_tsize()const;boolempty()constreturnsize()==0;size_tmax_size()const;另外,push_back(),insert()等也涉及到存储管理,后面另行介绍。1)max_size()返回vector理论上可以装的最多T的个数。这只是一个理论上的数字,大概是4GB/sizeof(T),没有多大实用价值。在程序中不要用。2)size()返回vector中实际装的T的个数。相当于CArray::GetSize()。3)empty()如果vector中没有任何T对象,返回true。也就是返回size()==0。4)clear();清除vector中的所有T对象。执行后empty()返回true。大致相当于resize(0),但不要求T可被缺省构造。相当于CArray::RemoveAll()。5)resize(size_tn,Tt=T());将vector中的元素个数设置为n,n可以大于size()也可以小于size。如果n小于size(),那么vector中下标为n..size()-1的元素都将被解构。如果n>size(),那么将在vector的后面新增加n-size()个相同的元素t。在增大vector时,可能发生存储再次分配。总之,调用resize(n,t)后,(size()==n)成立。请注意,如果调用resize(n)不带参数t,那么T必须可以缺省构造。6)reserve(size_tn);事先分配至少可以保存n个T对象的空间。调用后(capacity()>=n)成立。7)capacity();返回已经分配的存储空间够容纳的T类型对象的个数。后续的增加元素操作(如push_back(),insert())如果增加元素后vector中的总元素个数不超过capacity(),那么vector的实现保证不重新分配存储空间。vector管理的动态存储空间是连续的。执行操作IntVectorv(7,1);//sevenones.v.reserve(12);后,v的状态可以用下图表示:/--size()---\|1|1|1|1|1|1|1|-|-|-|-|-|\--capacity()---------/其中,1是已经构造的int类型的对象,-是可以构造一个int类型的对象,但还没有构造的原始空间。再执行v.push_back(2);v.push_back(3);后,v的状态可用下图表示:/----size()-----\|1|1|1|1|1|1|1|2|3|-|-|-|\----capacity()-------/执行resize(11,4);后:/----size()---------\|1|1|1|1|1|1|1|2|3|4|4|-|\----capacity()-------/capacity()>=size()总是成立的。对于下标为[size()..capacity()-1]的未构造对象的存储空间,是不可以访问的:v[11]=5;//undefinedbehavior-anythingcanhappen.7.添加元素到vector中下列操作添加元素到vector中,并可能引起存储分配:voidpush_back(Tconst&t);voidinsert(iteratorpos,Tconst&t=T());voidinsert(iteratorpos,size_tn,Tconst&t);templatevoidinsert(iteratorpos,Iterfirst,Iterlast);push_back()是把一个元素添加到vector的末尾。insert()是把一个t,或n个t,或从first开始到last结束的一个序列插入到pos指示的位置之前。当插入元素后size()将会大于capacity()时,将引起自动存储分配。vector将会分配一个比需要的存储区大若干倍(通常是1.5到2)的新的存储区,把老的元素拷贝过去,同时完成添加或插入,然后释放老的存储区。这就是说,vector自动存储分配的空间大小是指数式增长的,这可以保证多次添加元素到vector中时,平均用时是接近于常数的。IntVectorv;//add0,1,,99tov:for(inti=0;i<100;++i)v.push_back(i);//append9,8,7,,0totheend:inta[]=9,8,7,6,5,4,3,2,1,0;v.insert(v.end(),a,a+10);8.删除元素下列成员函数完成元素删除:voiderase(iterator);voiderase(iteratorfirst,iteratorlast);voidpop_back();voidclear();这些函数分别删除一个,一串,最后一个,或全部元素。IntVectorv;for(inti=0;i<100;++i)v.push_back(i);//删除50,51,,89:v.erase(v.begin()+50,v.end()-10);//删除49,48:v.pop_back();v.pop_back();//全部删除:v.clear();注意,删除操作不会引起存储分配,因此capacity()不变。以上是关于CArray数组对象序列化问题的主要内容,如果未能解决你的问题,请参考以下文章
Jackson ObjectMapper 反序列化包含对象数组的对象
如何使用 Jackson 反序列化来自 json 对象的对象数组