




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
/:數(shù)據(jù)類型與語法作者:謝興轉(zhuǎn)載需注明出處Symbian系統(tǒng)已經(jīng)提供了一套已經(jīng)定義好的內(nèi)置的數(shù)據(jù)類型。為了保證你的代碼是編譯器無關(guān)的,應(yīng)當(dāng)使用下面symbian系統(tǒng)提供的數(shù)據(jù)類型,而不要使用原生數(shù)據(jù)類型(nativetypes,這里指標(biāo)準(zhǔn)C中的int,char等)。根本類型TIntX和TUintX(其中X=8,16和32)分別用來表示8位,16位和32位的有符號(hào)和無符號(hào)的整數(shù)。一般情況下,使用TInt和TUint就可以了,除非是在考慮代碼優(yōu)化或兼容性的時(shí)候,才會(huì)用到TInt8,TInt16這樣的類型。TInt或TUint類型分別對(duì)應(yīng)有符號(hào)和無符號(hào)的整數(shù)。TInt64.在版本8.0之前,Symbian系統(tǒng)中不支持64位的算術(shù)運(yùn)算,而是用兩個(gè)32位的值來實(shí)現(xiàn)64位的整數(shù),在8.0版本之后,TInt64和TUInt64才被定義為longlong類型,真正使用64位的內(nèi)置數(shù)據(jù)類型。TReal32和TReal64(TReal相當(dāng)于TReal64)這兩個(gè)數(shù)據(jù)類型相當(dāng)于單精度和雙精度的浮點(diǎn)數(shù),由于浮點(diǎn)數(shù)的運(yùn)算要比整數(shù)慢,所以一般應(yīng)盡量防止使用浮點(diǎn)數(shù)的運(yùn)算。TTextX(其中X=8或16)分別對(duì)應(yīng)窄或?qū)挼淖址ㄗⅲ核^窄字符通常ASCII碼字符,而寬字符是指unicode字符集的字符)TAny*TAny*意為指向任意內(nèi)容的指針,在這種意義上講,TAny相當(dāng)于void,TAny*相當(dāng)于TAny*。但是,在某些場(chǎng)合下,void標(biāo)示‘空’,如:voidhello(void);這時(shí),不要將它改寫為:TAnyhello(TAny);TBool標(biāo)示布爾類型。Symbian系統(tǒng)提供了兩個(gè)常量:ETrue(=1)和EFalse(=0),分別表示真和假。注意:在Symbian系統(tǒng)中,TBool被定義為int,而ETrue和EFalse被定義為enum,所以,如果一個(gè)函數(shù)的返回值為TBool,不要用如下的代碼來比較函數(shù)的返回值:TBoolisLarger(TInta,TIntb){return(a>b)?ETrue:EFalse;}if(isLarger(4,3)==ETrue){...}//錯(cuò)誤,編譯不過。if(isLarger(4,3)){...}//正確2類和對(duì)象2.1Symbian系統(tǒng)中的命名習(xí)慣:在Symbian系統(tǒng)中編寫代碼時(shí),應(yīng)當(dāng)遵守種樣幾個(gè)規(guī)則:成員變量的命名以小寫字母i開頭,方法的參數(shù)以小寫字母a開頭,例如:classPernon{public: TIntiAge; voidSetAge(TIntaAge){iAge=aAge};}在symbian系統(tǒng)中存在幾種不同類型的類(class),不同類型的類,其特性也各不相同。有的在堆(heap)上創(chuàng)立,有的在棧(stack)上創(chuàng)立,特別的是,類的實(shí)例(instance)的去除方式也不盡相同(下面,為了方便我們把類的類別稱為型別)。型別(classtype)可以表達(dá)這些不同的特點(diǎn)。每個(gè)型別都有一套定義好的關(guān)于如何創(chuàng)立和去除實(shí)例的規(guī)則。為了容易區(qū)分型別,Symbian系統(tǒng)使用了一個(gè)簡(jiǎn)單的命名規(guī)則:類名以大寫字母開頭(T,C,R或M)。作為類的設(shè)計(jì)者,你先要考慮這個(gè)類的行為,看它到底與哪種型別匹配,一旦確定了它的類型,然后你就可以專注于該類的功能。同樣,對(duì)一個(gè)類的使用者來講,如果他不熟悉這個(gè)類,但類的命名規(guī)則可以幫助他弄清你的意圖如何用平安的方式初始化、使用和銷毀一個(gè)類的對(duì)象(object)。下面,我主要討論不同型別的主要特性。T類T類的行為類似于C++中的內(nèi)置類型,因此,它們以T作前綴(〞T〞代表〞Type〞)。象內(nèi)置類型一樣,它們沒有析構(gòu)方法(destructor),這導(dǎo)致的結(jié)果是:T類不能包含具有析構(gòu)方法的成員變量。所以,一般情況下,T類的成員變量只能是內(nèi)置類型的數(shù)據(jù)或者是其它的T類的對(duì)象。在某些的情況下T類也可以包含其它對(duì)象的指針或引用,不過,這時(shí)它們之前是“使用〞關(guān)系,而不是“擁有〞關(guān)系(也就是說,這個(gè)T類對(duì)象并不負(fù)責(zé)對(duì)成員的創(chuàng)立和銷毀的工作)。不能擁有外部數(shù)據(jù)的原因是因?yàn)門類沒有析構(gòu)方法。正是由于沒有析構(gòu)方法,T類的對(duì)象可以在棧上創(chuàng)立,當(dāng)程序流程退出函數(shù)或產(chǎn)生leave(一種代碼異常)的時(shí)候,系統(tǒng)自動(dòng)去除它。即使T類有一個(gè)析構(gòu)方法,在發(fā)生異常(在Symbian系統(tǒng)中,異常被稱為leave)時(shí)Symbian系統(tǒng)也不會(huì)調(diào)用它,因?yàn)閘eave沒有模仿標(biāo)準(zhǔn)C++的拋出異常的做法。T類的對(duì)象也可以在堆上創(chuàng)立。但是,應(yīng)當(dāng)在調(diào)用有可能發(fā)生異常的代碼之前,將這個(gè)對(duì)象放入到去除棧(cleanupStack),在發(fā)生異常的時(shí)候,去除棧(cleanupStack)會(huì)釋放這個(gè)對(duì)象。C類這種類都是從CBase派生來的(直接或間接)。//.hfileclassCStudent:publicCBase{ public: CStudent(){ RDebug::Print(_L("iamastudent")); }; ~CStudent() { RDebug::Print(_L("please,don'tkillme!")); } voidSampleFunction(){}; private: TIntiCode; TIntiScore;};CBase有兩個(gè)特點(diǎn):首先,它有一個(gè)虛的析構(gòu)方法,這樣,可以通過CBase指針來刪除它的子類。代碼如下所示:CBase*pStu=newCStudent();deletepStu;結(jié)果:iamastudentplease,don'tkillme!其次,CBase類和它的子類,重載了new操作符,這使得當(dāng)它在堆上創(chuàng)立的時(shí)候,自動(dòng)初始化為0,也就是說,當(dāng)它一開始被創(chuàng)立出來的時(shí)候,所有的成員變量都被初始化為0,所以您不必在構(gòu)造方法中去做這件事情。但是,在棧上創(chuàng)立對(duì)象時(shí),情況并非這樣,因?yàn)檫@時(shí)沒有用到new操作。這將潛在地導(dǎo)致堆上創(chuàng)立的對(duì)象和棧上創(chuàng)立的對(duì)象的行為不一致。因此,C類的對(duì)象一定要在堆上創(chuàng)立。很明顯,當(dāng)一個(gè)堆上的C類對(duì)象不再被需要時(shí),我們需要消耗它。一個(gè)C類的對(duì)象可能以兩種方式存在:其它類的指針成員變量或是一個(gè)局部的針指變量。在前一種情況下,我們可以在類的析構(gòu)方法中調(diào)用delete來刪除它;后一種情況要復(fù)雜一些,在調(diào)用任何有潛在的異常(leave)的代碼之前,要把這個(gè)指針放到去除棧(cleanupstack)中,否則有可能發(fā)生內(nèi)存泄露。CBase類聲明了私有的拷貝構(gòu)造方法和賦值操作(=)。這是一個(gè)很好的策略,它可以用來防止客戶代碼不小心地使用了淺拷貝或賦值的方法。由于基類的拷貝構(gòu)造和賦值是私有的,所以,如果您希望您的類可以能夠使用拷貝構(gòu)造方法,您必須顯式地聲明和定義拷貝構(gòu)造方法和賦值操作。但是,考慮到C類的特性,深拷貝可能造成發(fā)生異常(leave)的隱患,而您絕對(duì)不能讓類的構(gòu)造方法(或析構(gòu)方法)發(fā)生異常(我們?cè)诒窘坛痰暮竺娼忉屧颍?。所以,如果您確實(shí)需要一個(gè)拷貝的方法,那么您可以為類添加一個(gè)的可能會(huì)發(fā)生異常的方法來完成同樣的任務(wù),例如:CloneL()或CopyL()。如果您提供的這個(gè)類是從CBase派生的,您就不必為了防止客戶代碼使用有潛在平安問題的“淺〞拷貝,而在代碼中將這些方法聲明為私有的。R類前綴“R〞在這里代表資源(Resource),通常是外部資源,例如:文件的句柄(handle)。和C類不同,Symbian系統(tǒng)中不存在一個(gè)對(duì)應(yīng)的RBase類,所以一個(gè)R類應(yīng)當(dāng)有一個(gè)構(gòu)造方法來將它的資源句柄置為0,說明還沒有資源和這個(gè)新建的對(duì)象關(guān)聯(lián)在一起。但是,不要在構(gòu)造方法中初始化資源句柄,因?yàn)檫@樣有可能使構(gòu)造方法產(chǎn)生異常。R類中常常有類如Open(),Create()或Initialize()這樣的方法,它們用來分配資源,設(shè)置句柄成員變量的值,并返回錯(cuò)誤代碼或是產(chǎn)生異常。R類通常也有對(duì)應(yīng)的Close()或Reset()類,用來釋放資源,重置句柄的值說明沒有資源和該對(duì)象關(guān)聯(lián)。使用R類時(shí),一個(gè)常見的錯(cuò)誤是忘記調(diào)用它的Close()方法(當(dāng)然,該方法也可以是其它名字,但它經(jīng)常被命名為Close())或是有一個(gè)析構(gòu)方法釋放資源,這會(huì)引起資源的泄露。R類通常都很小,除了資源句柄沒有其它的成員變量。因?yàn)椴恍枰?。它通常也沒有析構(gòu)方法,資源的釋放都是在Close()方法中進(jìn)行的。大多數(shù)情況下,R類都是作為類的成員變量或局部變量存在的。只有少數(shù)情況下,在堆上創(chuàng)立。您必須確保,當(dāng)程序發(fā)后異常的時(shí)候,資源能被正確地釋放通常是使用資源棧。如果一個(gè)R類是一個(gè)堆上的自動(dòng)變量(相對(duì)于成員變量),您一但要保證資源被釋放,而且,變量本身也要被釋放。typicallybyusingtwopushcalls:CleanupClosePushL(),orasimilarfunction,toensurethattheresourceiscleanedup,andastandardCleanupStack::PushL(TAny*)whichsimplycallsUser::Free()ontheheapcell.R類的成員變量通常都很簡(jiǎn)單,所以一般不需要深拷貝(bitwisecopy)。R類的拷貝可能會(huì)引起混亂(想象一下:如果兩個(gè)對(duì)象同時(shí)在一個(gè)資源句柄上調(diào)用Close()方法,或兩個(gè)對(duì)象都沒有釋放資源,會(huì)發(fā)生什么情況?)如果,您想阻止任何對(duì)R類的拷貝,您應(yīng)當(dāng)聲明(但不定義)一個(gè)私有的構(gòu)造方法和賦值操作。M類當(dāng)提到多繼承的時(shí)候,它意味著從一個(gè)主要的類派生,同時(shí)也混雜基它類的功能。前綴M是單詞Mixin的首字母。Symbian系統(tǒng)不贊成多繼承的做法,因?yàn)檫@個(gè)引入額外的復(fù)雜性,M類是一個(gè)抽象類,它的作用相當(dāng)于java中的接口(interface)。在Symbian系統(tǒng)中,M類常被用來定義回調(diào)接口或者是觀察者(observer)類。M類也可以被其它類繼承。下面我們給出兩個(gè)例子。classMAnimal{ public: virtualvoidEatL()=0;};classMDomesticAnimal:publicMAnimal{ public: virtualvoidNameL()=0;};classCCat:publicCBase,publicMDomesticAnimal{ public: virtualvoidEatL(){};//從MAnimal,經(jīng)過MDomesticAnimal繼承 virtualvoidNameL(){};//從MDomesticAnimal繼承 //Otherfunctionsomittedforclarity};上面的例子演示了一個(gè)從CBase類和一個(gè)M類派生的具體類。而類MDomesticAnimal又是從MAnimal派生的。象接口一樣,由于不能被實(shí)例化,M類只能有虛(virtual)函數(shù),不能有成員變量和構(gòu)造方法。但它可以有析構(gòu)方法,條件是,實(shí)現(xiàn)它的具體類必須是從CBase派生的。在定義完類以后,然后可以用使用它。代碼如下:CCat*cat1=newCCat;deletecat1;//正確然下面的代碼卻是錯(cuò)誤的。MAnimal*cat2=newCCat;deletecat1;//錯(cuò)誤當(dāng)用M類的指針引用一個(gè)對(duì)象的時(shí)候,如果用delete刪除這個(gè)指針,則這個(gè)M類必須提供一個(gè)虛擬的析構(gòu)方法,否則會(huì)出現(xiàn)系統(tǒng)異常(paniccode42)。將MAnimal的代碼改寫,則上面代碼沒有問題。classMAnimal{ public: virtualvoidEatL()=0; virtual~MAnimal();//增加一個(gè)虛的析構(gòu)方法。};3描述符(descriptor)在Symbian系統(tǒng)中,字符串被稱為“描述符〞(descriptor),因?yàn)樗鼈兪亲晕颐枋龅?。在描述符中保存了它所表示的字符串的長(zhǎng)度和它的底層的內(nèi)存布局的信息。描述符比標(biāo)準(zhǔn)C中的字符數(shù)組和字符指針要復(fù)雜,您可能需要多花些時(shí)間來學(xué)習(xí)和掌握它的用法。關(guān)鍵是,它們的特殊設(shè)計(jì)使得它們?cè)谏倭績(jī)?nèi)存的設(shè)備上非常有效率,僅用非常少的內(nèi)存就可以保存自己的長(zhǎng)度和內(nèi)存布局的信息?,F(xiàn)在,讓我們來深入了解描述符的設(shè)計(jì)思想。在Symbian系統(tǒng)中,描述符是相當(dāng)讓人迷惑的,因?yàn)樗姆N類繁多。不同種類的描述符具有不同的特性和用法,但又經(jīng)常能相互轉(zhuǎn)換。它們不同于標(biāo)準(zhǔn)C++中的string,java語言中的string類或MFC中的CString,因?yàn)槌绦騿T必須自己管理底層的內(nèi)存分配和去除工作。它們具有防治內(nèi)存溢出的機(jī)制,并且不依賴NULL終結(jié)符號(hào)來決定字符串的長(zhǎng)度,從這方而來講,它也不同于C語言中的字符串?,F(xiàn)在我們來討論:什么是描述符?它們是如何工作的?在探討這些不同的描述符之前,先讓我們需要弄清楚一個(gè)根本的概念:什么是字符串?dāng)?shù)據(jù)的“寬度〞?這個(gè)長(zhǎng)度指的是單個(gè)字符是8bit的,還是16bit的寬度。在早期的版本中,字符的寬度都是8bit的,后來為了支持Unicode字符集,從第5版起,Symbian系統(tǒng)將16bit的字符作為標(biāo)準(zhǔn)。Symbian系統(tǒng)現(xiàn)在支持這兩種字符長(zhǎng)度的描述符,除了Copy()和Size()兩個(gè)方法以外,這兩種寬度的描述符的行為是完全一致的,這兩個(gè)方法的使用,我們后面再介紹。另外,有一套中立的描述符類型,它們既可以被定義為窄的描述符類型,也可以被定義為寬的描述符類型,這要取決于編譯時(shí)的寬度。您可以從它的名字上很容易看出這個(gè)類型所表示的寬度。假設(shè),它以8結(jié)尾(例如:TPtr8,就意味著它表示是的8bit的窄字符,而以16結(jié)尾的描述符類(例如:TPtr16)則操作16bit的寬字符。對(duì)中立(neutral)的類型來講,沒有數(shù)字結(jié)尾(例如:TPtr),在Symbian系統(tǒng)第5版以后,默認(rèn)的情況下,它們表示寬度為16bit的字符串。它們之間的關(guān)系比較類似于TInt,TInt16或TInt32之間的關(guān)系,這一點(diǎn)應(yīng)當(dāng)是比較易于理解的。一般情況下,您沒有必要指明是字符串的寬度,用中立的類型就可以了,這樣使你的代碼易于在寬字符版本和窄字符版本之間轉(zhuǎn)換(有過編程經(jīng)驗(yàn)的朋友應(yīng)該有這樣的印象,我們平常寫代碼,大多情況下,僅僅使用UINT類型,而較少考慮使用UINT16,UINT32類型)。另外一個(gè)問題是:描述符和字面量(literal)的區(qū)別。所謂字面量是指在編碼的時(shí)候就已經(jīng)確定的量,例如,標(biāo)準(zhǔn)C中的char*p="Helloworld";其中的"Helloworld"就是字面量。在Symbian系統(tǒng)中,對(duì)它們的處理是很不一樣的,這點(diǎn)我們?cè)诤竺嬖俳榻B。有了這樣的一些認(rèn)識(shí),現(xiàn)在我們可以來看看有哪些描述符類型。在Symbian系統(tǒng)中描述符類型有兩大種類:不可修改(non-modifiable)的描述符和可修改(modifiable)的描述符。3.1不可修改(non-modifiable)的描述符在Symbian系統(tǒng)中,所有的描述符都繼承自TDesC,在前面我們已經(jīng)討論了類名前綴T所代表的意義,在這里,我們更關(guān)心類名的后綴C所代表的意義,這個(gè)C是單詞Constant的首字符,表示這個(gè)類是不可更改的。這個(gè)類提供了一些用來返回字符串的長(zhǎng)度和操作數(shù)據(jù)的方法。Length()方法返回了描述符的長(zhǎng)度,因?yàn)?,每個(gè)描述符對(duì)象在內(nèi)存中的布局都是同樣的,用4個(gè)字節(jié)來表示它所包含的數(shù)據(jù)的長(zhǎng)度(實(shí)際上,只用了32個(gè)bit中的28個(gè)bit,剩余的4bit留作它用,所以描述符能表示的最大的長(zhǎng)度為228字節(jié),256MB,不過這已經(jīng)足夠了)。所以,Length()方法沒有被它的子類重寫,它對(duì)所有子類都有效。但是,根據(jù)實(shí)現(xiàn)子類的方法的不同,子類訪問數(shù)據(jù)的方式也不一樣,Symbian系統(tǒng)不要求它的子類通過虛函數(shù)的方式來實(shí)現(xiàn)自己的訪問數(shù)據(jù)的方法。不用虛函數(shù)重寫的原因是因?yàn)?,虛函?shù)會(huì)給每個(gè)被派生的描述符對(duì)象增加4節(jié)字的額外負(fù)擔(dān),c++用這4個(gè)字節(jié)來存放指向虛函數(shù)表的指針。我們前面說過,在設(shè)計(jì)描述符的時(shí)候要讓它盡可能高效,額外的字節(jié)開銷被認(rèn)為是不理想的。存放長(zhǎng)度的4個(gè)字節(jié)中,28bit用來表示長(zhǎng)度,剩下的4bit用來表示描述符的類型。目前,symbian系統(tǒng)中有5種派生的描述符類型,4bit限制了描述符的種類最多只能有16種,但這已經(jīng)足夠了。子類可以通過調(diào)用基類TDesC的Ptr()方法來訪問描述符的數(shù)據(jù),Ptr()方法檢查這4個(gè)bit,確定描述符的類型并返回它的數(shù)據(jù)在內(nèi)存中的地址。當(dāng)然,這要求TDesC基類清楚它的子類的內(nèi)存布局,并在Ptr()方法中使用硬編碼的方法。后面,為了表述上的方便,我們也把這種不可修改的描述符也稱為常量描述符(constantdescriptor)總結(jié):不可修改的描述符類TDesC是所有的非字面量描述符的基類,它提供了確定描述符長(zhǎng)度和訪問數(shù)據(jù)的方法,另外,它實(shí)現(xiàn)了所有的您想用來處理常量字符串的操作。3.2可修改(modifiable)的描述符所有的可修改的描述符都從TDes基類派生,而TDes本身又是從TDesC派生的。TDes有一個(gè)額外的成員變量用來存放為該描述符分配數(shù)據(jù)的最大長(zhǎng)度。MaxLength()方法返回了這個(gè)最大的長(zhǎng)度。像TDesC中的Length()方法一樣,MaxLength()方法也不被TDes的子類繼承。 TDes類提供了一系列的方法,用來對(duì)可修改字符串?dāng)?shù)據(jù)的操作,包括對(duì)字符串的附加、填充和格式化操作。所有的這些方法都被派生類繼承,派生類只實(shí)現(xiàn)一些特定的構(gòu)造方法和復(fù)制賦值的方法。這些方法都不負(fù)責(zé)分配內(nèi)存,假設(shè)它們超過了描述符的數(shù)據(jù)長(zhǎng)度,例如,用Append()方法在某個(gè)字符串后面附加另一個(gè)字符串時(shí),在調(diào)用該方法之前,您必須確保有足夠的內(nèi)存空間。當(dāng)然,只要不超過描述符的最大存儲(chǔ)容量,描述符的長(zhǎng)度可以自由地伸縮。當(dāng)描述符長(zhǎng)度比最大長(zhǎng)度短的時(shí)候,描述符的后面局部是多余未用的。這些方法使用了斷言(assertion)來確保描述符的最大長(zhǎng)度不會(huì)被超出。如果發(fā)生內(nèi)存溢出,將會(huì)產(chǎn)生一個(gè)panic(關(guān)于panic,我們將在后面的章節(jié)介紹),這樣可以方便您檢查和修正程序的錯(cuò)誤。事實(shí)上,不可能使描述符溢出,這一點(diǎn)保證了您代碼的強(qiáng)壯性,而且不易產(chǎn)生難以跟蹤的內(nèi)存陷阱。但需要注意的是,由于基類的構(gòu)造方法是proteced類型的,所以您無法直接實(shí)例化一個(gè)TDesC或TDes類的實(shí)例。現(xiàn)在我們來看看描述符的派生類,您可以實(shí)例化和使用派生類的對(duì)象。正如前面所說,這個(gè)地方是比較讓人迷惑的,因?yàn)槊枋龇嬖诖罅康呐缮?。前面,我們已?jīng)解釋過為什么每個(gè)類會(huì)有三個(gè)不同的版本,例如:TDes8,TDes16和TDes,分別對(duì)應(yīng)窄字符,寬字符和中立的類?,F(xiàn)在,讓我們看看有哪些主要的描述符類型,在深入討論每種類型的細(xì)節(jié)之前,我們先考察一下它們?cè)谝话闱闆r下的內(nèi)存布局。描述符有兩種根本的內(nèi)存布局:指針描述符和緩存區(qū)描述符。不同之處在于,指針描述符持有一個(gè)指向字符串的指針,而這個(gè)字符串存儲(chǔ)在內(nèi)存中的基它位置。與指針描述符不同,緩存區(qū)描述符本身持有字符數(shù)據(jù),也就是說字符數(shù)據(jù)本身構(gòu)成了描述符的一局部??偨Y(jié):TDes是所有的可修改的描述符的基類,并且它自己也是從TDesC派生的。它有一個(gè)能返回最大的內(nèi)存容量的方法和一系列的用來修改字符串?dāng)?shù)據(jù)的方法。3.3指針描述符(pointerdescriptor)指針描述符可分為兩種:TPtrC和TPtr(我們前面說過,每種類型的描述符,按照字符寬度,都可以分為三個(gè)版本,例如:窄字符版本TPtrC8,寬字窄版本TPtrC16和中立的版本TPtrC,所以嚴(yán)格來講,有六種指針描述符)。指針描述符所持有的字符串是跟描述符本身分開來存放的,它可以被存儲(chǔ)在ROM中,堆中或棧中。由于保存數(shù)據(jù)的內(nèi)存既不為描述符所擁有,也不通過它來管理。所以,如果要該描述符是在堆上分配的,那么應(yīng)通過堆描述符(HBufC,下面將要講解)來操作內(nèi)存的分配和銷毀;如果指針描述符所指向的字符串是在棧上分配的,那這個(gè)內(nèi)存必須是已經(jīng)在棧上分配好的。通常情況下,指針描述符是基于棧的,但有時(shí)候,它們也可以在堆上使用,例如:作為一個(gè)CBase派生類的成員變量的時(shí)候。在不可修改的描述符(TPtrC)中,指向數(shù)據(jù)的指針存放在長(zhǎng)度的后面,因此,指針描述符的總長(zhǎng)度為2個(gè)字(word);在可修改的指針描述符中,它存放在最大長(zhǎng)度的后面,因此,總長(zhǎng)度為3個(gè)字。下列圖比較了TPtr和TPtrC內(nèi)存布局.TPtrCTPtrC相當(dāng)于C語言中的constchar*。被它指向的數(shù)據(jù)可以被訪問但不能被修改:也就是說,描述符中的數(shù)據(jù)是常量。所有的從基類TDesC中繼承的操作都是可訪問的。TPtrC定義了一系列的構(gòu)造方法,使得它能從其它的描述符、指向內(nèi)存的指針或以0結(jié)尾的C語言字符串構(gòu)造。//字面量描述符將在后面介紹_LIT(KLiteralDes,"Sixtyzipperswerequicklypickedfromthewovenjutebag");TPtrCpangramPtr(KLiteralDes);//從字面量描述符構(gòu)造TPtrCcopyPtr(pangramPtr);//從其它的描述符構(gòu)造TBufC<100>constBuffer(KLiteralDes);//常量緩存區(qū)描述符,后面介紹TPtrCptr(constBuffer);//ConstructedfromaTBufC//TText8isasingle(8-bit)character,equivalenttounsignedcharconstTText8*cString=(TText8*)"Waltz,badnymph,forquickjigsvex"; //從以0結(jié)尾的字符串構(gòu)造TPtrC8anotherPtr(cString);TUint8*memoryLocation;//PointerintomemoryinitializedelsewhereTIntlength;//Lengthofmemorytoberepresented...TPtrC8memPtr(memoryLocation,length);//從一個(gè)指針構(gòu)造。這個(gè)指針本身可以改變成指向其他的字符串?dāng)?shù)據(jù)(通過Set()方法)。如果您想指明,不能改變您的TPtrC所指向的數(shù)據(jù),那么您可以將TPtrC聲明為const,這樣,當(dāng)您試圖用Set()方法更改TPtrC所指向的數(shù)據(jù)時(shí),編譯器會(huì)產(chǎn)生警告。//字面量描述符_LIT(KLiteralDes1,"Sixtyzipperswerequicklypickedfromthewovenjutebag");_LIT(KLiteralDes2,"Waltz,badnymph,forquickjigsvex");TPtrCalpha(KLiteralDes1);TPtrCbeta(KLiteralDes2);alpha.Set(KLiteralDes2);//alphapointstothedatainKLiteralDes2beta.Set(KLiteralDes1);//betapointstothedatainKLiteralDes1constTPtrCgamma(beta);//Pointstothedatainbeta,KLiteralDes1gamma.Set(alpha);//Generatesawarning,butpointstoalpha這里應(yīng)當(dāng)加一些示范代碼TPtrTPtr是可修改的指針描述符,它可用來訪問和修改字符串或二進(jìn)制數(shù)據(jù)。TDesC和TDes所提供的所有的操作都適用于TPtr。這個(gè)類定義了一些構(gòu)造方法,使得它能從指向內(nèi)存的指針構(gòu)造,并設(shè)置適當(dāng)?shù)拈L(zhǎng)度值和最大長(zhǎng)度值。編譯器也會(huì)產(chǎn)生隱式的構(gòu)造方法和拷貝構(gòu)造方法,因?yàn)樗鼈儧]有被聲明為保護(hù)的或私有的。一個(gè)TPtr對(duì)象可以從其它的可修改描述符構(gòu)造,例如:通過在不可修改的描述符上調(diào)用Des()方法,這個(gè)方法返回一個(gè)如下所示的TPtr對(duì)象:_LIT(KLiteralDes1,"Jackdawslovemybigsphinxofquartz");TBufC<60>buf(KLiteralDes1);//TBufCaredescribedlaterTPtrptr(buf.Des());//Copyconstruction;canmodifythedatainbufTIntlength=ptr.Length();//Length=37TIntmaxLength=ptr.MaxLength();//Maximumlength=60,asforbufTUint8*memoryLocation;//Validpointerintomemory...TIntlen=12;//LengthofdatatoberepresentedTIntmaxLen=32;//Maximumlengthtoberepresented//ConstructapointerdescriptorfromapointerintomemoryTPtr8memPtr(memoryLocation,maxLen);//length=0,maxlength=32TPtr8memPtr2(memoryLocation,len,maxLen);//length=12,max=32另外,TPtr提供了賦值運(yùn)算符=(),用來拷貝數(shù)據(jù)到指針?biāo)赶虻膬?nèi)存(數(shù)據(jù)源可以是可修改、不可修改的指針描述符,或以0結(jié)尾的字符串)。如果要拷貝的數(shù)據(jù)的長(zhǎng)度超過了描述符的最大長(zhǎng)度,會(huì)引發(fā)一個(gè)系統(tǒng)異常。像TPtrC一樣,TPtr也定義了一個(gè)Set()方法,用來改變描述符所指向的數(shù)據(jù)。_LIT(KLiteralDes1,"Jackdawslovemybigsphinxofquartz");TBufC<60>buf(KLiteralDes1);//TBufCaredescribedlaterTPtrptr(buf.Des());//PointstothecontentsofbufTUint16*memoryLocation;//Validpointerintomemory...TIntmaxLen=40;//MaximumlengthtoberepresentedTPtrmemPtr(memoryLocation,maxLen);//length=12,maxlength=40//CopyandreplacememPtr=ptr;//memPtrdataisKLiteralDes1(37bytes),maxLength=40_LIT(KLiteralDes2,"Thequickbrownfoxjumpsoverthelazydog");TBufC<100>buf2(KLiteralDes2);//TBufCaredescribedlaterTPtrptr2(buf2.Des());//Pointstothedatainbuf//Replacewhatptrpointstoptr.Set(ptr2);//ptrpointstocontentsofbuf2,maxlength=100memPtr=ptr2;//AttempttoupdatememPtrwhichpanicsbecausethe//contentsofptr2(43bytes)exceedsmaxlengthofmemPtr(40bytes)您一定不要混淆了Set()方法和=()賦值操作。前者將描述符的指針重置,使它指向新的數(shù)據(jù)區(qū)域,而后者將數(shù)據(jù)拷貝到描述符中,一般來說,這會(huì)更改描述符的長(zhǎng)度,但不會(huì)更改它的最大長(zhǎng)度值。3.5基于棧(stack-based)的緩沖區(qū)描述符基于緩沖區(qū)的描述符也可以分為可修改的TBuf和不可修改TBufC的兩種類型。對(duì)這種描述符來講,字符串?dāng)?shù)據(jù)本身就是描述符的一局部。下列圖給出了描述符的內(nèi)存布局:這兩種描述符通常用來存儲(chǔ)定長(zhǎng)的或相對(duì)較小的字符串,常用來存放長(zhǎng)度小于256個(gè)字符的文件名。類似于C語言中的char[],但是,它們具有檢查內(nèi)存溢出的功能。TBufC<n>TBufC<n>是不可修改的緩沖區(qū)類型,它主要用來存放字符串常量或是二進(jìn)制數(shù)據(jù)。該類從TBufCBase類派生,尖括號(hào)<>內(nèi)的數(shù)字表示分配給該描述符的數(shù)據(jù)區(qū)的大小。它定義了一些構(gòu)造方法,允許從其它的描述符或以0結(jié)尾的字符串構(gòu)造。也允許創(chuàng)立一個(gè)空的描述符,然后再填充。由于該描述符的數(shù)據(jù)是不可修改的,它的整個(gè)內(nèi)容可以被置換(通過該類的所定義的賦值操作),用來置換的數(shù)據(jù)可以是其它的不可修改的描述符或是0結(jié)尾的字符串,但是,無論是何種情況,新數(shù)據(jù)的長(zhǎng)度都不能超過長(zhǎng)度n(也就是創(chuàng)立該類的時(shí)候指定的模板參數(shù))。_LIT(KPalindrome,"Satan,oscillatemymetallicsonatas");TBufC<50>buf1(KPalindrome);//ConstructedfromliteraldescriptorTBufC<50>buf2(buf1);//Constructedfrombuf1//ConstructedfromaNULL-terminatedCstringTBufC<30>buf3((TText*)"Neveroddoreven");TBufC<50>buf4;//Constructedempty,length=0//Copyandreplacebuf4=buf1;//buf4containsdatacopiedfrombuf1,lengthmodifiedbuf1=buf3;//buf1containsdatacopiedfrombuf3,lengthmodifiedbuf3=buf2;//Panic!Maxlengthofbuf3isinsufficientforbuf2data該描述符中的數(shù)據(jù)可以被整體置換,但不能被直接修改,但有時(shí)候我們確實(shí)需要修改緩存區(qū)中的數(shù)據(jù),該怎么辦呢?系統(tǒng)提供了另一種途徑來修改數(shù)據(jù)。該類定義了Des()方法,它為緩存區(qū)中的數(shù)據(jù)返回一個(gè)可修改的指針描述符(TPtr)。我們可以通過這個(gè)指針描述符間接地修改緩沖區(qū)中的數(shù)據(jù)。當(dāng)數(shù)據(jù)通過指針描述符被修改以后,指針描述符和緩沖區(qū)描述符中的iLength的值會(huì)跟著改變,但要記住,緩存區(qū)描述符的長(zhǎng)度值只可能減小,而是不可能增大的,因?yàn)?,描述符類是不提供?nèi)存管理管理功能的。_LIT8(KPalindrome,"Satan,oscillatemymetallicsonatas");TBufC8<40>buf(KPalindrome);//ConstructedfromliteraldescriptorTPtr8ptr(buf.Des());//dataisthestringinbuf,maxlength=40//Illustratestheuseofptrtocopyandreplacecontentsofbufptr=(TText8*)"DoGeeseseeGod?";ASSERT(ptr.Length()==buf.Length());_LIT8(KPalindrome2,"Arewenotdrawnonward,wefew,drawnonwardtonewera?");ptr=KPalindrome2;//Panic!KPalindrome2exceedsmaxlengthofptr(=40)TBuf<n>這也是一個(gè)模板類,它是一個(gè)可修改的緩沖區(qū)描述符類,后面的<n>表示緩沖區(qū)大小。TBuf從TBufBase類派生,而TBufBase是從TDes派生的,因此,它繼承了TDes和TDesC類所有的方法。像TBufC<n>一樣,TBuf<n>也定義了一系列的構(gòu)造方法和賦值操作。對(duì)所有的描述符類型來講,內(nèi)存管理是您的責(zé)任,盡管這個(gè)緩沖區(qū)中的數(shù)據(jù)是可修改的,但它的長(zhǎng)度不能超過在構(gòu)造方法中所給定的最大值(n)。假設(shè)緩沖區(qū)的內(nèi)容需要擴(kuò)展,那么您必須決定是在編譯的時(shí)候就給定一個(gè)足夠大的值,或是在運(yùn)行的時(shí)候動(dòng)態(tài)分配內(nèi)存。但無論哪種情況,都要確保數(shù)據(jù)長(zhǎng)度不要超過緩存區(qū)的最大長(zhǎng)度。如果需要使用動(dòng)態(tài)分配的內(nèi)存,您可以使用基于堆的描述符,這個(gè)我們?cè)诤竺嬉v到。要是您覺得管理內(nèi)存分配的任務(wù)太過繁重,您也可以選擇使用動(dòng)態(tài)數(shù)組。不過,您應(yīng)當(dāng)記住,使用動(dòng)態(tài)數(shù)組的額外開銷是很高的。_LIT(KPalindrome,"Satan,oscillatemymetallicsonatas");TBuf<40>buf1(KPalindrome);//ConstructedfromliteraldescriptorTBuf<40>buf2(buf1);//ConstructedfromconstantbufferdescriptorTBuf8<40>buf3((TText8*)"DoGeeseseeGod?");//fromCstringTBuf<40>buf4;//Constructedempty,length=0,maximumlength=40//Illustratecopyandreplacebuf4=buf2;//buf2copiedintobuf4,updatinglengthandmaxlengthbuf3=(TText8*)"Murderforajarofredrum";//updatedfromCstring3.6基于堆的(Heap-Based)緩沖區(qū)描述符當(dāng)您要使用非常長(zhǎng)的字符串時(shí),有另外一種選擇:基于堆的描述符。它能擁有比它的創(chuàng)立者更長(zhǎng)的生存期。當(dāng)您在編譯的時(shí)候還不能確定緩沖區(qū)長(zhǎng)度的時(shí)候,堆描述符也是很有用的,這時(shí),它的作用相當(dāng)于C語言中的malloc。HBufC也許您已經(jīng)發(fā)現(xiàn),HBufC的類名以“H〞開頭,這不符合Symbian系統(tǒng)中慣用的命名習(xí)慣。這確實(shí)是一個(gè)特例,“H〞表示這個(gè)類一般是在堆(Heap)上分配的。HBufC定義了靜態(tài)的NewL()方法,用來在堆上創(chuàng)立一個(gè)緩存區(qū)。正如您所見到,HBufC中的字母“C〞表示這個(gè)表述符是不可修改的。對(duì)該類的操作幾乎和TBufC<n>一樣:該類提供了一套賦值操作,允許整個(gè)緩沖區(qū)中的內(nèi)容被替換掉;同樣,新內(nèi)容的長(zhǎng)度不能超過緩存區(qū)的大小,否則會(huì)引起系統(tǒng)異常;通過調(diào)用Des()方法,可以返回一個(gè)可修改的指針描述符(TPtr),可以通過這個(gè)指針描述符來更改緩沖區(qū)中的內(nèi)容。_LIT(KPalindrome,"DoGeeseseeGod?");TBufC<20>stackBuf(KPalindrome);//Allocatesanemptyheapdescriptorofmaxlength20HBufC*heapBuf=HBufC::NewLC(20);TIntlength=heapBuf->Length();//Currentlength=0TPtrptr(heapBuf->Des());//Modificationoftheheapdescriptorptr=stackBuf;//CopiesstackBufcontentsintoheapBuflength=heapBuf->Length();//length=17HBufC*heapBuf2=stackBuf.AllocLC();//Fromstackbufferlength=heapBuf2->Length();//length=17_LIT(KPalindrome2,"Palindrome");*heapBuf2=KPalindrome2;//CopyandreplacedatainheapBuf2length=heapBuf2->Length();//length=10CleanupStack::PopAndDestroy(2,heapBuf);記住,堆描述符可以按您的要求的尺寸動(dòng)態(tài)分配內(nèi)存,但它不會(huì)自動(dòng)按您的期望更改緩沖區(qū)的大小。在修改緩存區(qū)的內(nèi)容之前,您要確保緩存區(qū)的內(nèi)存是足夠的。為了幫您簡(jiǎn)化這些操作,HBufC提供的一套R(shí)eAllocL()方法,它可以用來擴(kuò)展堆的緩存區(qū)(這個(gè)操作有可能會(huì)使緩沖區(qū)從一個(gè)內(nèi)存區(qū)域搬到另一個(gè)區(qū)域)。IftheHBufC*isstoredonthecleanupstack,movingthepointerasaresultofmemoryreallocationcancausesigni.cantproblemseitherintheeventofaleaveorifthecleanupstack’sPopAndDestroy()functionisusedtodestroythememory.如果您在HBufC上調(diào)用Des()方法來獲取了TPtr,在經(jīng)過重新分配內(nèi)存后,TPtr中的成員變量iPtr有可能變成無效的。因此,為了確保平安,在重新分配內(nèi)存后,應(yīng)該再次調(diào)用Des()來創(chuàng)立一個(gè)新的TPtr對(duì)象。注:出于性能上的考慮,Symbian系統(tǒng)并沒有提供可修改的堆描述符HBuf??偨Y(jié):Symbian系統(tǒng)中總共有5種類型的描述符,TPtrC,PTtr,TBufC<n>,TBuf<n>和HBufC。下面的圖示說明了它們的繼承關(guān)系。3.7字面量描述符(LiteralDescriptors)下面我們來看看字面量描述符,它相當(dāng)于C語言中的staticchar[]。字面量描述符是通過一系列的宏來創(chuàng)立的,這些宏可在頭文件e32def.H中找到#define_L8(a)(TPtrC8((constTText8*)(a)))#define_S8(a)((constTText8*)a)#define_LIT8(name,s)conststaticTLitC8<sizeof(s)>name={sizeof(s)-1,s}#define_L16(a)(TPtrC16((constTText16*)L##a))#define_S16(a)((constTText16*)L##a)#define_LIT16(name,s)conststaticTLitC16<sizeof(L##s)/2>name={sizeof(L##s)/2-1,L##s}首先,我們來看_LIT,這是最有效率也是被使用得最多的一個(gè)。這個(gè)宏的用法如下:_LIT(KMyLiteralDescriptor,"Thequickbrownfoxjumpsoverthelazydog");后面KMyLiteralDescriptor就可以作為一個(gè)常量來使用,例如可以將它寫到文件或顯示給用戶。_LIT宏構(gòu)建了一個(gè)名為KMyLiteralDescriptor的TLitC16對(duì)象,其中保存了字符串的值(在這個(gè)例子中是Thequickbrownfoxjumpsoverthelazydog),在二進(jìn)制程序中可以找到這個(gè)值,因?yàn)樗潜粚懙轿募械摹H缒?,_LIT8和_LIT16的用法相似。因?yàn)槊枋龇膶挾葹?6bit,所以,在將C字節(jié)類型的字符串轉(zhuǎn)換為描述符能用的數(shù)據(jù)時(shí),宏將字符串的長(zhǎng)度除以2。作為參考,下面給出類TLitC16的定義,其中__TText被定義為寬的,16bit的字符。TLitC8也有類似的定義。template<TIntS>classTLitC16{public:inlineconstTDesC16*operator&()const;inlineoperatorconstTDesC16&()const;inlineconstTDesC16&operator()()const;...//Omittedforclaritypublic:TUintiTypeLength;__TTextiBuf[__Align16(S)];};template<TIntS>inlineconstTDesC16*TLitC16<S>::operator&()const{returnREINTERPRET_CAST(constTDesC16*,this);}template<TIntS>inlineconstTDesC16&TLitC16<S>::operator()()const{return*operator&();}template<TIntS>inlineTLitC16<S>::operatorconstTDesC16&()const{return*operator&();}從上面的定義中可以看到,TLitC16(和TLitC8)并不從TDesC8或TDesC16派生,但是它們與TBufC8或TBufC16具有相同的內(nèi)存布局。這就使得TLitC16(和TLitC8)可以用在任何可以使用TDesC的地方。您也可以用如下的方法從一個(gè)字面量構(gòu)造一個(gè)指針描述符:TPtrC8thePtr(KMyLiteralDescriptor);從字面量構(gòu)造緩沖區(qū)描述符需要一點(diǎn)小技巧。如果您用size()去獲得_LIT常量,它會(huì)返回相應(yīng)的TLitC對(duì)象的尺寸大小,這個(gè)尺寸相當(dāng)于描述符內(nèi)容的尺寸加上額外的8個(gè)byte(用來存放長(zhǎng)度值的4字節(jié)和表示結(jié)束符的NULL)。如果您想用它來構(gòu)造基于堆的描述符,必須要將這額外的8個(gè)字節(jié)考慮進(jìn)去。//定義一個(gè)包含44字符的字面量_LIT8(KExampleLit8,"Thequickbrownfoxjumpedoverthelazydog");TIntsize=sizeof(KExampleLit8);//52bytes(contents+8bytes)TBufC8<(sizeof(KExampleLit8)-8)>theStackBuffer(KExampleLit8);對(duì)基于堆的描述符,您可以用描述符實(shí)際內(nèi)容的長(zhǎng)度來分配緩沖區(qū),然后將內(nèi)容拷貝到描述符中。為了得到正確的長(zhǎng)度,您可以用公共(public)的成員變量iTypeLength,或者,也可以用更簡(jiǎn)單的方法,使用()操作符來將字面量轉(zhuǎn)換成一個(gè)描述符,然后用這個(gè)得到的描述符來得到內(nèi)容的長(zhǎng)度。但最簡(jiǎn)單的方法是,使用()操作符將對(duì)象轉(zhuǎn)換成描述符后,直接調(diào)用TDes::AllocL()方法,返回一個(gè)HBufC*,代碼如下:TIntdescriptorLength=KExampleLit8.iTypeLength;//44bytes//Formastackbufferdescriptoraroundtheliteral//CreateaheapbuffercopyingthecontentsoftheliteralHBufC8*theHeapBuffer=KExampleLit8().AllocL();//對(duì)寬字符字面量的操作類似_LIT16(KExampleLit16,"Thequickbrownfoxjumpedoverthelazydog");size=sizeof(KExampleLit16);//96bytes(contentsinbytes+8bytes)descriptorLength=KExampleLit16.iTypeLength;//44bytes(contents)用_L和_LIT生成的字面量,它們的內(nèi)存布局是有差異的,如下列圖所示:現(xiàn)在我們簡(jiǎn)單地看看_L和_S宏,這兩個(gè)宏已經(jīng)過時(shí),但在測(cè)試代碼中還經(jīng)常用到。RDebug::Print(_L("Helloworld!"));這個(gè)代碼的作用相當(dāng)于:_LIT(KLit,"Helloworld!");RDebug::Print(KLit);從上面的代碼可以看到,使用_L的好處在于,您可以直接使用它,而無需在使用之前,在別的地方聲明。字符串(〞Helloworld!〞)被作為一個(gè)根本的以0結(jié)尾的字符串寫到二進(jìn)制文件中,它前面沒有長(zhǎng)度值(這不同于_LIT產(chǎn)生的字符串)。由于沒有長(zhǎng)度值,字面量的內(nèi)存布局不同于描述符,并且當(dāng)代碼運(yùn)行的時(shí)候,_L的第個(gè)實(shí)例都會(huì)產(chǎn)生一個(gè)臨時(shí)的TPtrC,這個(gè)TPtrC的指針指向字面量的第一個(gè)字節(jié)在ROM中的存儲(chǔ)位置。只要是在創(chuàng)立該字面量的生存期中使用這個(gè)臨時(shí)的描述符,這都是平安的。然而,創(chuàng)立臨時(shí)變量要求設(shè)置指針、長(zhǎng)度和描述符的類型,這對(duì)內(nèi)聯(lián)的構(gòu)造方法來說是一個(gè)負(fù)擔(dān),如果代碼中有很多這樣的字面量,也會(huì)使得二進(jìn)制程序的體積增大。如果僅從存儲(chǔ)方式上看,_S宏和_L是相同的,但有一點(diǎn)不同它不產(chǎn)生臨時(shí)的TPtrC描述符。如果您僅將它作為以0結(jié)尾的描述符使用,那么就使用_S宏。到目前為止,我們已經(jīng)討論了關(guān)于描述符的根本知識(shí),包括如何實(shí)例化每一種具體的描述符,如何訪問和修改描述符的數(shù)據(jù),以及如何置換描述符的內(nèi)容。現(xiàn)在我們來關(guān)注一下操作數(shù)據(jù)的方法和在使用描述符時(shí)一些常見的問題。3.8描述符作參數(shù)和返回類型在編寫代碼的時(shí)候,您可能不想被限制于只能使用TBuf,原因是僅僅因?yàn)槟硞€(gè)特定的庫函數(shù)要求使用它。同樣的道理,作為函數(shù)的提供者,您可能對(duì)調(diào)用者傳遞進(jìn)來的參數(shù)類型不感興趣。事實(shí)上,您不應(yīng)該要求調(diào)用者傳遞特定類型的參數(shù),因?yàn)槟赡茉诤竺嬉薷暮瘮?shù)的實(shí)現(xiàn),您可能要改變描述符的類型,如果您將這樣的函數(shù)作為編程接口,最后您不得不讓您的客戶也改變他們的代碼。這樣的改動(dòng)是非常不理想的,因?yàn)樗茐牧舜a的兼容性。除非您來掌管描述符(負(fù)責(zé)描述符的創(chuàng)立和銷毀工作),您甚至可以不用知道描述符是基于堆的還是基于棧的。事實(shí)上,只要標(biāo)準(zhǔn)類型的描述符(我們前面提到的5種描述符類型之一),就可以在它上面調(diào)用適當(dāng)?shù)姆椒?,客戶代碼完全可以忽略描述符的內(nèi)存布局和它在內(nèi)存中的位置?;谝陨系脑颍?dāng)您定義函數(shù)的時(shí)候,應(yīng)當(dāng)盡量使用抽象的基類作為函數(shù)的參數(shù)和返回值。為了有效率,描述符參數(shù)應(yīng)當(dāng)使用引用傳遞的方式,要么是constTDesC&或者是TDes&。例如,類RFile定義了read()和write()方法IMPORT_CTIntWrite(constTDesC8&aDes);IMPORT_CTIntRead(TDes8&aDes)const;在這兩個(gè)方法中,輸入的描述符被顯式地聲明為8bit的寬度,這樣可以既寫入字符串,也可以寫入二進(jìn)制數(shù)據(jù)。被用來寫入到文件中的參數(shù)是對(duì)一個(gè)不可修改的描述符的引用,而在讀文件的時(shí)候,使用了可修改的描述符的引用??尚薷拿枋龇淖畲箝L(zhǎng)度決定了可以從文件中讀入多少數(shù)據(jù),所以不需要再給文件效勞器傳遞一個(gè)表示長(zhǎng)度的參數(shù)。文件效勞器將會(huì)填充滿描述符。當(dāng)文件中的數(shù)據(jù)不夠描述符的最大長(zhǎng)度時(shí),文件效勞器會(huì)把所有可得的數(shù)據(jù)寫入描述符。調(diào)用函數(shù)后,描述符的長(zhǎng)度反映了寫入數(shù)據(jù)的長(zhǎng)度。這樣,調(diào)用者也無需再另外傳遞一個(gè)參數(shù)用來表示返回的數(shù)據(jù)長(zhǎng)度。當(dāng)寫一個(gè)函數(shù)的時(shí)候,如果參數(shù)是可修改的描述符,實(shí)際上您不必考慮它是否有足夠的空間用來存放數(shù)據(jù),因?yàn)槊枋龇旧碛羞吔鐧z查的機(jī)制,如果出現(xiàn)了內(nèi)存溢出現(xiàn)象,會(huì)產(chǎn)生系統(tǒng)異常。當(dāng)然,您也可能不希望在描述符數(shù)據(jù)區(qū)過短的情況下,描述符的方法會(huì)發(fā)生系統(tǒng)異常。這時(shí),您應(yīng)當(dāng)在文檔中說明,如果描述符的長(zhǎng)度不夠?qū)?huì)如何處理。有時(shí)候,一個(gè)比較好的方法是,給調(diào)用者返回一個(gè)長(zhǎng)度值,這樣,調(diào)用者可以采用適當(dāng)?shù)牟襟E來分配一個(gè)正確長(zhǎng)度的描述符。HBufC*CPoem::DoGetLineL(TIntaLineNumber){//Codeomittedforclarity.Allocatesandreturnsaheapbuffer//containingthetextofaLineNumber(leavesifaLineNumberis//outofrange)}voidCPoem::GetLineL(TIntaLineNumber,TDes&aDes){HBufC*line=DoGetLineL(aLineNumber);CleanupStack::PushL(line);//Isthedescriptorlargeenough(4bytesormore)toreturnan//integerrepresentingthelengthofdatarequired?if(aDes.MaxLength()<line->Length()){if(aDes.MaxLength()>=sizeof(TInt)){//Writesthelengthrequired(TPckgisdescribedlater)TPckg<TInt>length(line->Length());aDes.Copy(length);}//Leave&indicatethatthecurrentlengthistooshortUser::Leave(KErrOverflow);//LeavesaredescribedinChapter2}else{aDes.Copy(*line);CleanupStack::PopAndDestroy(line);}}另一個(gè)方案是,在函數(shù)中分配堆緩沖區(qū),把它返還給調(diào)用者,由調(diào)用者負(fù)責(zé)銷毀它。3.9常用的方法Ptr()基類TDesC實(shí)現(xiàn)了Ptr()方法,用來訪問描述符的數(shù)據(jù),該方法返回一個(gè)指向字符數(shù)組首地址的指針。您可以通過這個(gè)指針來直接操作字符串?dāng)?shù)據(jù)。代碼如下所示:Size()和Length()TDesC實(shí)現(xiàn)了Size()andLength()方法,前者返回描述符所占有的字節(jié)數(shù),而后者返回的是描述符的字符長(zhǎng)度。對(duì)8bit的描述符來講,它們是相等的,而對(duì)16bit的描述來說,Size()返回的數(shù)值是Length()的兩倍。MaxLength()可修改的描述符TDes實(shí)現(xiàn)的這個(gè)方法返回描述符的最大長(zhǎng)度。SetLength()和SetMax()前者用來設(shè)置描述符的長(zhǎng)度,這個(gè)長(zhǎng)度值必須是小于描述符的最大長(zhǎng)度的,否則會(huì)引起系統(tǒng)異常。后者將描述符的當(dāng)前長(zhǎng)度設(shè)置成最大值,注意,它不并不能擴(kuò)展描述符數(shù)據(jù)區(qū)的長(zhǎng)度。Zero()和FillZ()前者將描述符的長(zhǎng)度設(shè)置為0,而后者是用0來來填充描述符的內(nèi)容置。如果您要用其它字符填充描述符的內(nèi)容,可用Fill()方法。這個(gè)方案類似于C語言中的memset()函數(shù)。Copy()TDes實(shí)現(xiàn)了一系列的重的Copy()方法,下面是其中的兩個(gè):IMPORT_CvoidCopy(constTDesC8&aDes);IMPORT_CvoidCopy(constTDesC16&aDes);這些方法將參數(shù)描述符中的數(shù)據(jù)拷貝到目標(biāo)描述符中,同時(shí)為目標(biāo)描述符設(shè)置新的長(zhǎng)度。如可源描述符的長(zhǎng)度超過目標(biāo)描述符的最大長(zhǎng)度,將會(huì)引發(fā)一個(gè)系統(tǒng)異常。3.10使用HBufC堆描述符我們已經(jīng)討論過描述符的一些特性,現(xiàn)在來關(guān)注一下使用描述符時(shí)經(jīng)常容易范的錯(cuò)誤。首先,我們將創(chuàng)立和使用堆描述符HBufC。前面提到過,在已有的描述符上調(diào)用Alloc()或AllocL()方法,可以產(chǎn)生一個(gè)新的HBufC。這里是一個(gè)例子:voidCSampleClass::UnnecessaryCodeL(constTDesC&aDes){iHeapBuffer=HBufC::NewL(aDes.Length());TPtrptr(iHeapBuffer->Des());ptr.Copy(aDes);...//以上代碼完全可以被下面的代替,下面代碼更有效率。iHeapBuffer=aDes.AllocL();}Anothercommonwaytointroducecomplexityoccursintheoppositedirection,thatis,thegenerationofTDesC&fromaheapdescriptor.當(dāng)從一個(gè)堆描述符產(chǎn)生一個(gè)TDesC&的時(shí)候,也容易范一個(gè)錯(cuò)誤,這個(gè)錯(cuò)誤同樣為代碼增加了復(fù)雜性。代碼如下所示:constTDesC&CSampleClass::MoreAccidentalComplexity(){return(iHeapBuffer->Des());//以上代碼完全可以寫成return(*iHeapBuffer);//這樣更簡(jiǎn)潔高效}另外一個(gè)比較微妙問題是,當(dāng)您分配一個(gè)HBufC以后,然后在它上面調(diào)用Des(),可以返回一個(gè)TPtr對(duì)象。HBufC*buf=HBufC::NewL(9);TPtrp=buf->Des();可是,假設(shè)您回憶一下,可以知道在HBufC中,并沒有一個(gè)字(word)用來保存最大長(zhǎng)度的信息因?yàn)镠BufC是不可修改的(non-modifiable),它不需要最大長(zhǎng)度的信息。然而,,TPtr需要這個(gè)最大長(zhǎng)度的信息,這時(shí)問題來了,您從哪里得到這個(gè)最大長(zhǎng)度呢?答案在于:當(dāng)您調(diào)用Des()的時(shí)候,系統(tǒng)用HBufC的最大
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 孩子受傷家長(zhǎng)協(xié)議書
- 房屋破損重修協(xié)議書
- 2025年03月臺(tái)州市黃巖區(qū)事業(yè)單位公開招聘100人【編制】筆試歷年典型考題(歷年真題考點(diǎn))解題思路附帶答案詳解
- 直聯(lián)式真空泵項(xiàng)目風(fēng)險(xiǎn)評(píng)估報(bào)告
- 遼寧省葫蘆島協(xié)作校2025年高三下學(xué)期第二次驗(yàn)收考試數(shù)學(xué)試題試卷含解析
- 壓電陶瓷元件項(xiàng)目安全風(fēng)險(xiǎn)評(píng)價(jià)報(bào)告
- 哈爾濱北方航空職業(yè)技術(shù)學(xué)院《建設(shè)項(xiàng)目管理軟件及應(yīng)用》2023-2024學(xué)年第二學(xué)期期末試卷
- 正德職業(yè)技術(shù)學(xué)院《科學(xué)計(jì)算基礎(chǔ)》2023-2024學(xué)年第一學(xué)期期末試卷
- 湖南鐵路科技職業(yè)技術(shù)學(xué)院《舞蹈二》2023-2024學(xué)年第二學(xué)期期末試卷
- 醫(yī)院連鎖項(xiàng)目安全評(píng)估報(bào)告
- 項(xiàng)目質(zhì)量管理機(jī)構(gòu)結(jié)構(gòu)框圖
- 保險(xiǎn)公司首轉(zhuǎn)對(duì)團(tuán)隊(duì)的意義方法課件
- TAVI(經(jīng)皮導(dǎo)管主動(dòng)脈瓣植入術(shù))術(shù)后護(hù)理
- 6.3.1 平面向量基本定理 課件(共15張PPT)
- 建筑消防設(shè)施巡查記錄
- 混凝土護(hù)欄檢查記錄表
- DBJ04∕T 258-2016 建筑地基基礎(chǔ)勘察設(shè)計(jì)規(guī)范
- 綜合探究三 探尋絲綢之路(課堂運(yùn)用)
- 職業(yè)危害防治實(shí)施管理臺(tái)賬
- 社會(huì)團(tuán)體民辦非清算審計(jì)報(bào)告模板
- 建筑工程質(zhì)量檢測(cè)收費(fèi)項(xiàng)目及標(biāo)準(zhǔn)表67262
評(píng)論
0/150
提交評(píng)論