《C++程序設(shè)計(jì)》課件第7章_第1頁(yè)
《C++程序設(shè)計(jì)》課件第7章_第2頁(yè)
《C++程序設(shè)計(jì)》課件第7章_第3頁(yè)
《C++程序設(shè)計(jì)》課件第7章_第4頁(yè)
《C++程序設(shè)計(jì)》課件第7章_第5頁(yè)
已閱讀5頁(yè),還剩58頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第7章const和inline7.1const變量 137.2const成員變量與成員函數(shù)7.3內(nèi)聯(lián)函數(shù)本章小結(jié)習(xí)題

const問(wèn)題一直是C++語(yǔ)言設(shè)計(jì)中的一個(gè)難題。很多從C轉(zhuǎn)成C++?的程序員可能還是會(huì)經(jīng)常使用#define這種宏定義來(lái)聲明常量,但是對(duì)于程序來(lái)說(shuō),用const來(lái)聲明常量會(huì)更加靈活。比如用const聲明常量時(shí)可以有數(shù)據(jù)類(lèi)型,而#define這種常量的聲明就沒(méi)有數(shù)據(jù)類(lèi)型,這樣便于編譯器對(duì)其進(jìn)行數(shù)據(jù)類(lèi)型的安全性檢查等。7.1const變量通俗地講,常量就是常數(shù),或代表固定不變值的名字。在程序中,如果想讓某個(gè)變量的內(nèi)容從初始化后就一直保持不變,就可以定義一個(gè)常量。被const修飾的對(duì)象都受到保護(hù),可以防止在程序中其他的地方被意外地改動(dòng),從而提高程序的健壯性。7.1.1const與值替代

1.內(nèi)部常量在C++中,平常使用的內(nèi)部數(shù)據(jù)類(lèi)型的值都可以稱(chēng)作是值常量,下面介紹幾種內(nèi)部數(shù)據(jù)類(lèi)型的常量。(1)實(shí)數(shù)型常量:在C++中,有兩種實(shí)數(shù)(即浮點(diǎn)數(shù)):一種是帶有小數(shù)點(diǎn)的,還有一種就是指數(shù)型的:小數(shù)點(diǎn)型:1.23 指數(shù)型:1.23e2或1.23E2(2)整型常量:十進(jìn)制:10 八進(jìn)制:012 十六進(jìn)制:0X12(3)字符常量:普通字符:'a' 特殊字符:'\n'(4)字符串常量:

"Helloworld“(5)枚舉常量:

enumday{Mon,Tue,Wends,Thu,F(xiàn)ri,Sat,Sun};在這里,Mon的值默認(rèn)為0,后面依次加1。2.const聲明常量下面來(lái)看看在程序中定義的常量。如果在整個(gè)程序的編寫(xiě)中,在很多地方都需要用到一個(gè)常數(shù)時(shí),那么,在這些地方的一個(gè)或多個(gè)地方寫(xiě)錯(cuò)了這個(gè)值的話(huà),就會(huì)導(dǎo)致計(jì)算錯(cuò)誤。這時(shí),可以給這個(gè)常數(shù)取一個(gè)名字,在每處常數(shù)被使用的地方都用這個(gè)名字代替,那么編譯器只需要檢查這個(gè)名字的拼寫(xiě)錯(cuò)誤,這樣能更容易地避免數(shù)值的不一致性導(dǎo)致的計(jì)算錯(cuò)誤。舉個(gè)常見(jiàn)的例子,在編寫(xiě)很多關(guān)于圓的周長(zhǎng)或面積的計(jì)算公式的程序時(shí),經(jīng)常需要使用到圓周率p,此時(shí),可以通過(guò)命名一個(gè)容易理解并且便于記憶的名字來(lái)改進(jìn)程序的可讀性,并且在定義的時(shí)候?yàn)槠浼由详P(guān)鍵字const來(lái)進(jìn)行修飾,為其加上常量的性質(zhì),來(lái)幫助預(yù)防程序出現(xiàn)數(shù)值一致性的錯(cuò)誤。由于圓周率p不屬于C++語(yǔ)言的字符描述集的范圍,因此不能直接當(dāng)作C++程序中的變量名,所以可以用另外的名字來(lái)表示:

constfloatpi=3.141592653;

在這里,細(xì)心的讀者可能會(huì)提出疑問(wèn):float型的變量能存儲(chǔ)上面所有小數(shù)點(diǎn)后的數(shù)值嗎?不錯(cuò),的確不行!因?yàn)樵贑++中利用const關(guān)鍵字來(lái)聲明常量的時(shí)候是需要指定數(shù)據(jù)類(lèi)型的,而且C++的編譯器會(huì)進(jìn)行類(lèi)型的檢查。由于float型只能存儲(chǔ)7位有效精度的實(shí)數(shù),因此在上面的聲明中,pi的實(shí)際值是3.141593,最后的3位是不起作用的,而且最后一位會(huì)四舍五入。如果將上面定義中的float型改為double型,則能夠完全存儲(chǔ)上面小數(shù)點(diǎn)后的數(shù)值。

在將某變量利用const關(guān)鍵字修飾之后,程序中的任何語(yǔ)句對(duì)它都只能讀取值而不能修改,這樣可以防止該變量的值在程序中被無(wú)意中修改。也正是由于常量不能被修改,因此,常量必須在定義時(shí)就初始化,而不能像下面的代碼:

constfloatpi;pi=3.1415926;

這樣做是錯(cuò)誤的,常量的名稱(chēng)永遠(yuǎn)都不能放在賦值語(yǔ)句的左邊。由于常量在程序運(yùn)行之前就已經(jīng)知道了它的值,即在編譯時(shí)就能求值了,因此在定義常量時(shí),對(duì)其進(jìn)行初始化的值可以是一個(gè)常量的表達(dá)式。但是這個(gè)常量表達(dá)式中不能含有某個(gè)函數(shù),因?yàn)橐话愕暮瘮?shù)都是在程序運(yùn)行時(shí)才能返回具體的值,在編譯時(shí)是無(wú)法獲取其返回值的。不過(guò)有一點(diǎn)比較容易混淆,即類(lèi)似于sizeof()這種看起來(lái)像函數(shù)的表達(dá)式,它其實(shí)是C++中的基本操作符,它在編譯時(shí)就可以確定返回值了,所以這種表達(dá)式可以出現(xiàn)在常量的賦值語(yǔ)句中。其實(shí)在C語(yǔ)言中就已出現(xiàn)了const,用來(lái)聲明常量,但是C語(yǔ)言中的const對(duì)數(shù)據(jù)的修飾僅僅是表明這是一個(gè)不能再被更改的普通變量,而且對(duì)該變量的數(shù)據(jù)類(lèi)型沒(méi)有說(shuō)明。

3.const聲明變量在C語(yǔ)言中,const關(guān)鍵字的主要作用是定義常量、修飾函數(shù)參數(shù)和修飾函數(shù)返回值這三個(gè);在C++中,const關(guān)鍵字不僅有這三個(gè)作用,而且還能修飾函數(shù)的定義體和定義類(lèi)中某個(gè)函數(shù)為恒態(tài)函數(shù),即無(wú)法改變類(lèi)中的數(shù)據(jù)成員。

此外,在C語(yǔ)言中,const修飾變量時(shí)是需要占用系統(tǒng)內(nèi)存的,并且它的名字是全局符。這也使得C語(yǔ)言的編譯器不能把const修飾的對(duì)象當(dāng)作是一個(gè)編譯期間的常量。例如:

constsize=100;

chara[size];

看起來(lái)這兩個(gè)語(yǔ)句是正確的,是合理的聲明,但是這段C程序卻會(huì)得到一個(gè)編譯的錯(cuò)誤。其原因是,在C語(yǔ)言中,用const修飾的變量size占用了內(nèi)存的某個(gè)地址,故C語(yǔ)言的編譯器得不到它在編譯時(shí)的值,因此會(huì)出現(xiàn)編譯的錯(cuò)誤。在C語(yǔ)言當(dāng)中,直接用const加上變量名即可聲明一個(gè)常量,和#define一樣,無(wú)需指定該變量的數(shù)據(jù)類(lèi)型。但是在C++中不行,在C++中使用const修飾變量時(shí)必須同時(shí)聲明該變量的數(shù)據(jù)類(lèi)型,這也是面向?qū)ο蟪绦蛟O(shè)計(jì)的一個(gè)特性的體現(xiàn)。

在C語(yǔ)言中還可以這樣使用const來(lái)修飾變量:

constsize;

C語(yǔ)言的編譯器把這看做是一個(gè)合理的聲明,這個(gè)聲明表示在別的地方有內(nèi)存分配,在這里進(jìn)行引用。但是這樣在C++中是不允許的,因?yàn)樵贑語(yǔ)言中默認(rèn)const是外部連接的,而在C++中默認(rèn)const是內(nèi)部連接的,所以在C++中僅僅這樣聲明是不正確的。如果想用C++達(dá)到上面同樣的目的,必須顯式地用extern將內(nèi)部連接改為外部連接:

externconstsize;這樣,C++的編譯器也能知道這是一個(gè)聲明,表示在別的地方有內(nèi)存分配。當(dāng)然,這樣顯式地在C語(yǔ)言中聲明也是可以的,但是由于在C語(yǔ)言中默認(rèn)的就是外部連接,所以這樣使用沒(méi)有太大的意義。4.const與?#define的區(qū)別其實(shí),從某種意義上來(lái)說(shuō),在C語(yǔ)言當(dāng)中使用const的意義也不大。在前面曾提到,用const修飾的變量在編譯期間必須知道它的值,所以即使在常數(shù)表達(dá)式里想使用一個(gè)已命名的值,用const的效率并不如在預(yù)處理器中使用#define的高。因此在C語(yǔ)言里,建議還是使用#define來(lái)聲明常量。

const常量和?#define聲明的宏常量的區(qū)別如下:

(1)在C++中聲明的const常量是有數(shù)據(jù)類(lèi)型的,而用#define聲明的常量是沒(méi)有數(shù)據(jù)類(lèi)型的。因此,C++的編譯器可以對(duì)常量進(jìn)行數(shù)據(jù)類(lèi)型的安全性檢查,而C語(yǔ)言的編譯器只是對(duì)?#define聲明的常量進(jìn)行字符的替代,這樣對(duì)數(shù)據(jù)類(lèi)型不僅沒(méi)有安全性檢查,而且在字符替代的過(guò)程中,可能會(huì)產(chǎn)生意料不到的錯(cuò)誤,比如邊際效應(yīng)等。

(2)很多集成化的編譯工具在對(duì)C++程序進(jìn)行編譯時(shí),可以對(duì)const常量進(jìn)行調(diào)試,但是對(duì)于C語(yǔ)言中的宏常量是無(wú)法進(jìn)行調(diào)試的,所以在C++中使用const常量對(duì)程序的調(diào)試也是有很大幫助的。

(3)使用const常量比?#define形式更節(jié)省空間,避免不必要的內(nèi)存分配。例如:

#defineA10 //宏定義

constinta=10; //const常量定義,此時(shí)并沒(méi)有將a放入ROM中

intb=A; //編譯期間會(huì)進(jìn)行宏替換,需要分配內(nèi)存intc=a; //此時(shí)會(huì)為a分配內(nèi)存,以后不再分配

intd=A; //編譯期間會(huì)進(jìn)行宏替換,需要再次分配內(nèi)存

inte=a; //不需要分配內(nèi)存7.1.2常量指針與指針常量

1.常量指針當(dāng)一個(gè)指針?biāo)赶虻膬?nèi)容是不能被修改的內(nèi)存空間時(shí),稱(chēng)這個(gè)指針為常量指針。例如:

constinta=100;constint*p=&a;

此時(shí),就稱(chēng)p為常量指針,因?yàn)橹羔榩指向的是一個(gè)常量,它占據(jù)的內(nèi)存空間是不能被外界所修改的。因?yàn)槌A渴遣荒苄薷牡?,所以下面通過(guò)指針的賦值操作是錯(cuò)誤的:*p=200;常量指針的含義是指針指向了一個(gè)不能再被修改的變量,而這個(gè)指針本身是可以修改的,例如可以將上面的指針p再指向另一個(gè)常量:

constintb=200;p=&b;

這時(shí)指針p還是一個(gè)常量指針,只是它指向的是另一個(gè)常量而已,當(dāng)然在這里還是不能為*p去賦值。

常量指針有一個(gè)很特殊的用法,還是以上面已經(jīng)定義的常量指針p為例:

intc=300;p=&c;*p=400; //錯(cuò)誤

c=400; //正確變量c并不是常量,所以它可以被修改,但是為什么還是不能對(duì)*p進(jìn)行賦值呢?這是因?yàn)槎x了一個(gè)指向某個(gè)常量的指針,只是限制了這個(gè)指針的間接訪(fǎng)問(wèn)操作,而不能規(guī)定這個(gè)指針?biāo)赶虻闹灯浔旧淼牟僮鞯囊?guī)定性。就像上面將常量指針指向一個(gè)普通的變量,這樣就可以保護(hù)被指向的變量在指針的操作中無(wú)法被修改,但是可以直接操作這個(gè)非常量的值。這種用法在函數(shù)傳遞中會(huì)被經(jīng)常使用到。

下面來(lái)看看函數(shù)傳遞時(shí)const的用法:

#include<iostream>usingnamespacestd;voidmyStrcpy(char*destStr,constchar*sourceStr){ while(*destStr++=*sourceStr++) ;}intmain(){ chara[15]="Helloworld!"; charb[15]; myStrcpy(b,a); cout<<b<<endl; return0;}

運(yùn)行結(jié)果如下:char型的數(shù)組a本來(lái)是一個(gè)變量,但是在傳遞給函數(shù)strcpy作為參數(shù)時(shí),被常量指針修飾之后就成為不能被修改的常量了,這樣就不允許對(duì)源字符串進(jìn)行任何修改。因?yàn)樵趯har型數(shù)組a傳遞給strcpy函數(shù)時(shí),相當(dāng)于執(zhí)行了以下操作:constint*sourceStr=&a;所以在函數(shù)體里,*sourceStr是個(gè)常量,不能將*sourceStr作為左值進(jìn)行任何操作,從而達(dá)到保護(hù)源字符串的目的。當(dāng)然,在主函數(shù)中,數(shù)組a還是一個(gè)普通的變量,不受任何約束,可以隨時(shí)被修改。2.指針常量從字面意思就可以粗略地看出,指針常量是指這個(gè)指針本身就是一個(gè)常量。和常量指針相反,指針常量所指向的內(nèi)存空間的值是可以修改的,但是這個(gè)指針本身是不能被修改的。例如:

#include<iostream>usingnamespacestd;intmain(){ chara='B'; char*constp=&a; *p='A'; cout<<*p<<endl; return0;}

運(yùn)行結(jié)果如下:

因?yàn)閜是指針常量,它本身是不能被修改的,所以它不能出現(xiàn)在賦值語(yǔ)句的左側(cè),否則將會(huì)引起編譯錯(cuò)誤。指針常量在初始化時(shí)和普通常量一樣,既然不能被修改,那么在定義指針常量時(shí)就必須初始化。

由于*p并不是常量,因此可以對(duì)其進(jìn)行修改,例如還可以這樣做:*(p+1)

此時(shí),可以對(duì)指針p所指向的內(nèi)存區(qū)域的下一個(gè)字節(jié)進(jìn)行操作。既然有指向常量的指針,也有指針常量,那么當(dāng)然可以定義一個(gè)指向常量的指針常量:

constinta=10;constint*constp=&a;

這時(shí),指針p指向的是一個(gè)常量,所以*p值是不能被修改的,而指針p本身也是一個(gè)指針常量,因此指針p也是不能被修改的,即p所指向的地址是不能被修改的。所以此時(shí)p和*p都不能作為賦值語(yǔ)句的左值而被修改。7.1.3常量引用在很多時(shí)候,函數(shù)需要將非內(nèi)部數(shù)據(jù)類(lèi)型(如程序員自己定義的類(lèi))的對(duì)象作為參數(shù),而這樣的函數(shù)的運(yùn)行效率是非常低的。因?yàn)樵谶\(yùn)行期間,在函數(shù)體的內(nèi)部將會(huì)產(chǎn)生非內(nèi)部數(shù)據(jù)類(lèi)型的臨時(shí)對(duì)象用于復(fù)制其作為參數(shù)的對(duì)象,而臨時(shí)對(duì)象的構(gòu)造、析構(gòu)以及賦值的操作都將消耗系統(tǒng)資源。例如:

classA{ …};voidfunction(Aa){ …}

這時(shí),為了提高效率,可以將函數(shù)參數(shù)中的類(lèi)對(duì)象改為類(lèi)對(duì)象的引用,這僅僅是借用了一下別名而已,不會(huì)產(chǎn)生非內(nèi)部數(shù)據(jù)類(lèi)型的對(duì)象,這樣可以大大提高程序的效率。但是,這樣做也有一個(gè)不足的地方,就是引用在傳遞的過(guò)程中有可能改變?cè)瓕?duì)象的值,這不是希望看到的。為了解決這個(gè)問(wèn)題,只需要為這個(gè)引用加上const關(guān)鍵字來(lái)修飾即可:

voidfunction(constA&a)

這樣,不但不會(huì)對(duì)原對(duì)象的值有任何影響,而且比用指針更簡(jiǎn)單些,體現(xiàn)了使用const所帶來(lái)的安全性。

在C++中的引用不像指針那樣,分常量指針和指針常量,C++是不會(huì)區(qū)分某個(gè)變量的const引用和const變量的引用的。因?yàn)槟阌肋h(yuǎn)都不可能給引用本身去重新賦值,使它去指向另外一個(gè)變量,而且引用總是const的,所以無(wú)所謂什么常量引用和引用常量了。因此,像前面那樣對(duì)引用應(yīng)用const關(guān)鍵字來(lái)修飾,其作用只是使引用的目標(biāo)成為const變量,所以你不可能看到這樣的情況:

constintconst&a=1;7.1.4傳遞const值在很多時(shí)候,在調(diào)用某個(gè)需要參數(shù)的函數(shù)時(shí),并不希望在它的函數(shù)體內(nèi)將這個(gè)參數(shù)進(jìn)行任何修改,而僅僅是將值“借給”這個(gè)函數(shù)當(dāng)作參數(shù)來(lái)使用,通常是在將值傳遞給該函數(shù)時(shí)加上關(guān)鍵字const進(jìn)行修飾以達(dá)到這個(gè)目的。下面簡(jiǎn)單看一下這種傳遞const值的方法:

voidfunction(constinta){ …}

這樣,在主函數(shù)中調(diào)用函數(shù)function時(shí),用相應(yīng)的變量初始化const修飾的常量,在函數(shù)體中就可以按照被const修飾的內(nèi)容進(jìn)行常量化,而為該函數(shù)傳遞的參數(shù)值在該函數(shù)體內(nèi)是無(wú)法被修改的。前面兩個(gè)小節(jié)介紹的用const修飾指針或引用作為函數(shù)的參數(shù)來(lái)傳遞值,就屬于傳遞const值的特殊情況。因?yàn)楫?dāng)參數(shù)采用指針或引用來(lái)傳遞時(shí),可以防止指針或引用所指向的內(nèi)容被意外修改。在一般的程序中,使用const指針或const引用來(lái)傳遞函數(shù)的參數(shù)的情況較為普遍,而一般在僅僅是內(nèi)部數(shù)據(jù)類(lèi)型的值傳遞時(shí),建議盡量不要用const關(guān)鍵字來(lái)進(jìn)行修飾。因?yàn)閷?duì)于內(nèi)部數(shù)數(shù)據(jù)類(lèi)型的參數(shù),函數(shù)本身會(huì)自動(dòng)產(chǎn)生一個(gè)臨時(shí)變量來(lái)復(fù)制該參數(shù)的內(nèi)容,而且作為內(nèi)部數(shù)據(jù)類(lèi)型,不存在構(gòu)造和析構(gòu)的問(wèn)題,復(fù)制的過(guò)程也很快,不會(huì)消耗多少系統(tǒng)資源。這樣,這個(gè)內(nèi)部數(shù)據(jù)類(lèi)型的參數(shù)本來(lái)就無(wú)需保護(hù),所以這個(gè)時(shí)候更不需要利用const關(guān)鍵字來(lái)進(jìn)行修飾,以此達(dá)到對(duì)該參數(shù)的保護(hù)目的。當(dāng)然,顯式地使用const來(lái)修飾也不會(huì)產(chǎn)生錯(cuò)誤,對(duì)于一些C++的初學(xué)者,可能還會(huì)有加深理解的作用。其實(shí),還有一種方法可以確保在函數(shù)內(nèi)部的執(zhí)行不會(huì)影響到函數(shù)外部傳遞給函數(shù)的參數(shù),就是在函數(shù)體的內(nèi)部定義另外一個(gè)變量來(lái)復(fù)制這個(gè)參數(shù)的值。例如:voidfunction(inta){ constint&b=a; …}

這樣,在函數(shù)體內(nèi)部只需要對(duì)變量b進(jìn)行操作即可。關(guān)于傳遞const值,有一個(gè)需要特別注意的地方,就是const只能修飾輸入函數(shù)。如果函數(shù)的某個(gè)參數(shù)是作為輸出使用的,那么這個(gè)時(shí)候,不論采用的是const指針傳遞還是const引用傳遞,都不能用const關(guān)鍵字來(lái)進(jìn)行修飾,否則這個(gè)函數(shù)將失去輸出的功能??傊?,通過(guò)使用常量參數(shù),函數(shù)的調(diào)用者可以保證他們所傳遞給函數(shù)的對(duì)象不會(huì)在函數(shù)執(zhí)行過(guò)程中被改變,也不會(huì)對(duì)函數(shù)的執(zhí)行帶來(lái)任何其他影響。7.1.5返回const值當(dāng)希望函數(shù)的返回值在使用時(shí)不被外界改變時(shí),可以為其加上const關(guān)鍵字來(lái)進(jìn)行修飾。當(dāng)然,如果一個(gè)函數(shù)的返回值是void,那么就完全不用const來(lái)對(duì)返回值進(jìn)行修飾了。其實(shí),不僅僅是對(duì)于void型的函數(shù)返回值,如果函數(shù)返回的是內(nèi)部數(shù)據(jù)類(lèi)型,也不必用const對(duì)返回值進(jìn)行修飾。例如:

constintfunction(inta){ …}

該函數(shù)返回的是int型的值,即返回的本來(lái)就是一個(gè)數(shù)值,當(dāng)然不可能再通過(guò)賦值語(yǔ)句對(duì)其進(jìn)行重新賦值。所以,一般來(lái)說(shuō),當(dāng)函數(shù)的返回類(lèi)型為內(nèi)部數(shù)據(jù)類(lèi)型時(shí),建議最好將const關(guān)鍵字去掉。當(dāng)函數(shù)返回非內(nèi)部數(shù)據(jù)類(lèi)型(即程序員自己定義的類(lèi))的對(duì)象或這個(gè)對(duì)象的引用時(shí),也最好不使用const關(guān)鍵字進(jìn)行修飾,因?yàn)榇藭r(shí)返回值如果具有const常量屬性,則返回的實(shí)例只能訪(fǎng)問(wèn)這個(gè)自定義類(lèi)的public成員、protected成員和const成員函數(shù)(在下一小節(jié)將介紹),而且不允許對(duì)這些成員進(jìn)行賦值操作,這在一般的軟件設(shè)計(jì)中出現(xiàn)的幾率比較小。所以,不建議為返回值為某個(gè)自定義類(lèi)的對(duì)象或?qū)ο蟮囊玫暮瘮?shù)加上const來(lái)修飾返回值。

當(dāng)然,并不是當(dāng)所有的函數(shù)返回類(lèi)對(duì)象時(shí)都不適用const來(lái)修飾返回值,只是一般情況下,此時(shí),用const修飾返回值的情況多用于二元操作符的重載并會(huì)產(chǎn)生新對(duì)象的情況。當(dāng)函數(shù)的返回值為指針時(shí),應(yīng)為函數(shù)的返回值加上const關(guān)鍵字,那么該函數(shù)返回的指針不能被用在賦值語(yǔ)句的左側(cè)而被修改,它只能賦值給被const關(guān)鍵字修飾的同類(lèi)型的指針。例如:

constchar*function();constchar*p=function();

而下面的語(yǔ)句將會(huì)出現(xiàn)編譯錯(cuò)誤:

char*p=function();7.2const成員變量與成員函數(shù)1.const成員變量和普通變量一樣,在構(gòu)造一個(gè)類(lèi)的時(shí)候,也可以為這個(gè)類(lèi)的某些成員加上const關(guān)鍵字來(lái)修飾,使其成為const數(shù)據(jù)成員。而對(duì)于const成員變量,需要注意的是,由于它必須被初始化而且又不能被更新,那么在構(gòu)造函數(shù)中,只能使用初始化成員列表來(lái)對(duì)其進(jìn)行初始化,如果試圖在構(gòu)造函數(shù)的函數(shù)體內(nèi)或者該類(lèi)的其他地方對(duì)const成員變量進(jìn)行初始化或修改,都會(huì)引起編譯錯(cuò)誤。例如:

#include<iostream>usingnamespacestd;classA{ constinta;public: A(intb):a(b){}

intgetA() { returna; }};intmain(){ A*a=newA(10); cout<<a->getA()<<endl; return0;}

運(yùn)行結(jié)果如下:

因?yàn)镃++是一種面向?qū)ο蟮某绦蛟O(shè)計(jì)語(yǔ)言,所以,const成員變量也只是在該類(lèi)的某個(gè)對(duì)象的生存期間內(nèi)是常量,對(duì)于整個(gè)類(lèi)來(lái)說(shuō)則是可以改變的。因?yàn)檫@個(gè)類(lèi)可以創(chuàng)建很多個(gè)它自己的對(duì)象,而在這些不同的類(lèi)對(duì)象中,其const成員變量的值都可以互不相同。比如在上面的例子中,在創(chuàng)建類(lèi)A的對(duì)象時(shí),可以為其構(gòu)造函數(shù)傳入不同的參數(shù)提供給成員初始化列表,這樣,在不同的類(lèi)對(duì)象中,常量a就具有不同的值。所以,在類(lèi)的聲明中,不能對(duì)const成員變量進(jìn)行初始化。因?yàn)樵陬?lèi)的對(duì)象沒(méi)有被具體創(chuàng)建時(shí),編譯器無(wú)法知道某個(gè)具體對(duì)象的const成員變量的值是多少。

因此,類(lèi)中的const成員變量并不能使其在每一個(gè)類(lèi)對(duì)象中都具有固定的值,這樣在大型的項(xiàng)目開(kāi)發(fā)中可能會(huì)帶來(lái)一些不便。如果想要使用在整個(gè)類(lèi)中都是常量的成員,那么可以使用枚舉來(lái)實(shí)現(xiàn)。例如:

classA{ enum{a=10,b=20,…}; …};

此外,這種枚舉型的常量不會(huì)占用類(lèi)對(duì)象的存儲(chǔ)空間,編譯器在編譯期間就知道這些成員變量的值。不過(guò)這種使用方法的不足之處是,枚舉的默認(rèn)類(lèi)型為整型數(shù)據(jù),所以最大值是有限制的,而且不能表示浮點(diǎn)型的數(shù)據(jù)。2.const成員函數(shù)使用了const關(guān)鍵字進(jìn)行修飾的成員函數(shù),稱(chēng)之為const成員函數(shù)。例如:

voidfunction()const{ …}

當(dāng)某個(gè)類(lèi)中有const成員變量時(shí),這些const成員變量不像普通變量一樣能被該類(lèi)中的所有成員函數(shù)所訪(fǎng)問(wèn)或進(jìn)行操作,只有const成員函數(shù)才能訪(fǎng)問(wèn)或者操作類(lèi)中的常量成員或?qū)ο?,沒(méi)有加const修飾的成員函數(shù)試圖訪(fǎng)問(wèn)或操作const成員時(shí),編譯器為了保證這些成員的const特性,會(huì)引發(fā)編譯錯(cuò)誤。當(dāng)然,在const成員函數(shù)的內(nèi)部,也不能試圖去改變const成員變量的值。

從上面的const成員函數(shù)的聲明格式可以看出,const關(guān)鍵字是加在函數(shù)說(shuō)明的后面的,它是整個(gè)函數(shù)類(lèi)型說(shuō)明的一個(gè)組成部分,所以,是否為成員函數(shù)加上const關(guān)鍵字進(jìn)行修飾,是可以進(jìn)行函數(shù)重載的。而且,既然const成員函數(shù)要操作類(lèi)的const成員,那么在函數(shù)體的內(nèi)部,肯定還需要出現(xiàn)const關(guān)鍵字。前面講過(guò),const成員變量的初始化必須放在初始化成員列表中來(lái)進(jìn)行,構(gòu)造函數(shù)是不能對(duì)const成員變量進(jìn)行操作的,所以,構(gòu)造函數(shù)是不能聲明為const的。同理,析構(gòu)函數(shù)也不可以聲明為const的。

const成員函數(shù)能訪(fǎng)問(wèn)或操作const成員變量,當(dāng)然也能訪(fǎng)問(wèn)、操作不是const的成員變量,那么這樣做又有什么意義呢?

有些時(shí)候,雖然類(lèi)的某些數(shù)據(jù)成員沒(méi)有被const關(guān)鍵字加以修飾,但是在某個(gè)函數(shù)的函數(shù)體內(nèi),還是不希望這些數(shù)據(jù)成員被修改,那么,這時(shí)為函數(shù)加上const修飾就能達(dá)到不會(huì)修改任何數(shù)據(jù)成員的目的。如果在函數(shù)體內(nèi),不小心執(zhí)行了修改這些數(shù)據(jù)成員的操作,或者調(diào)用了其他的非const成員函數(shù)而引發(fā)某些操作時(shí),編譯器都將提示錯(cuò)誤,這樣能大大提高程序的健壯性。下面,通過(guò)具體的程序來(lái)理解為什么要給訪(fǎng)問(wèn)普通數(shù)據(jù)成員的函數(shù)加上const修飾。

classA{public: intadd(){number++} intgetValue()const;private: intnumber;};intA::getValue()const{ //++number; //編譯錯(cuò)誤,因?yàn)樵噲D修改數(shù)據(jù)成員

//add();//編譯錯(cuò)誤,因?yàn)樵噲D調(diào)用非const成員函數(shù)

returnnumber;}

這樣,在getValue()函數(shù)的執(zhí)行過(guò)程中,就能確保number的值不會(huì)被任何其他操作所修改。3.使用const的注意事項(xiàng)

(1)在能夠理解并且知道為什么要使用的情況下,要盡可能放心地去使用const關(guān)鍵字,這樣經(jīng)常可以提高程序的可讀性、可維護(hù)性以及健壯性。但是并不是說(shuō)const常量可以過(guò)多地使用。如果在某個(gè)頭文件中定義了一個(gè)常量,那么在程序鏈接時(shí),所有使用這個(gè)頭文件的代碼都將復(fù)制這個(gè)常量,如果用到該頭文件的代碼比較多,則會(huì)增加程序的可執(zhí)行文件的大小,在一個(gè)大的工程項(xiàng)目中,這是很影響效率的。所以,不要隨便將一個(gè)對(duì)象修飾為常量,要真正需要時(shí)才使用const關(guān)鍵字。

(2)永遠(yuǎn)不要將const修飾的成員放在賦值語(yǔ)句的左側(cè),試圖對(duì)其進(jìn)行修改,這是使用const關(guān)鍵字最基本的原則。(3)在傳遞參數(shù)時(shí),const關(guān)鍵字一般修飾指針或者引用,而不是內(nèi)部數(shù)據(jù)類(lèi)型或者是自定義類(lèi)的實(shí)例,因此這時(shí)的const關(guān)鍵字顯得沒(méi)有太大的意義。

(4)區(qū)分清楚并理解const和成員函數(shù)之間的關(guān)系:傳遞const值、返回const值和const成員函數(shù),const關(guān)鍵字要放在需要它的地方,并了解const放在不同地方的不同意義,不要輕易地將函數(shù)的返回值修飾為const。而且,除非是操作符重載時(shí),否則一般不要將函數(shù)的返回值的類(lèi)型聲明為對(duì)某個(gè)類(lèi)對(duì)象的const引用。

(5)應(yīng)該盡量將常量局部化,只在需要常量的模塊中定義就可以了,因?yàn)椴⒉皇撬械某A慷夹枰謥?lái)訪(fǎng)問(wèn),除非是整個(gè)工程項(xiàng)目都需要知道的關(guān)鍵常量。7.3內(nèi)聯(lián)函數(shù)在C++?程序中,一些局部的變量都是存放在棧里面,而系統(tǒng)的??臻g是有限的,在程序中,如果頻繁地去使用一些相同的函數(shù),就會(huì)大量地消耗??臻g,如果??臻g用盡了,那么程序的執(zhí)行就會(huì)出現(xiàn)錯(cuò)誤。不僅僅是函數(shù)的局部變量會(huì)帶來(lái)問(wèn)題,在某個(gè)函數(shù)被調(diào)用時(shí),其實(shí)是將程序執(zhí)行的順序轉(zhuǎn)移到該函數(shù)在內(nèi)存中存放的地址,在調(diào)用完該函數(shù)之后,程序的執(zhí)行將跳轉(zhuǎn)回原來(lái)的地址,繼續(xù)執(zhí)行原來(lái)的內(nèi)容。這就要求在調(diào)用該函數(shù)之前,需要記錄調(diào)用者原來(lái)的執(zhí)行地址,調(diào)用完畢后需要返回所記錄的地址并繼續(xù)往下執(zhí)行,這在時(shí)間和空間上都會(huì)有一定的消耗,影響整個(gè)程序的執(zhí)行效率。

為了解決這個(gè)問(wèn)題,在C++中特別地引入了內(nèi)聯(lián)函數(shù),用inline關(guān)鍵字來(lái)修飾。

7.3.1inline和編譯器通過(guò)以下程序來(lái)看看內(nèi)聯(lián)函數(shù)是如何解決上述問(wèn)題的:

#include<iostream>#include<string>usingnamespacestd;inlinestringfunction(inta){ return(a%2==0)?"偶數(shù)":"奇數(shù)";}voidmain(){ for(inti=0;i<10;i++) { cout<<i<<":"<<function(i)<<endl;}}

如果沒(méi)有用inline來(lái)修飾函數(shù),那么在主函數(shù)中的循環(huán)內(nèi)部將調(diào)用10次function()函數(shù),這樣,就會(huì)反復(fù)在棧中為function()的局部變量開(kāi)辟內(nèi)存,這將消耗大量的棧空間。

為函數(shù)function()加上inline關(guān)鍵字進(jìn)行修飾后,它就成了一個(gè)內(nèi)聯(lián)函數(shù),在主函數(shù)的執(zhí)行過(guò)程之前,編譯器已經(jīng)將每次的function()函數(shù)調(diào)用都替換成:

return(a%2==0)?"偶數(shù)":"奇數(shù)";

這樣,就不會(huì)因?yàn)榉磸?fù)調(diào)用函數(shù)并為其局部變量反復(fù)開(kāi)辟??臻g了。因?yàn)樵诔绦蚓幾g時(shí),編譯器就已經(jīng)將程序中出現(xiàn)的調(diào)用內(nèi)聯(lián)函數(shù)的表達(dá)式都用內(nèi)聯(lián)函數(shù)的函數(shù)體中的語(yǔ)句進(jìn)行了替換。這樣,既不用反復(fù)地為函數(shù)的局部變量在棧中開(kāi)辟內(nèi)存空間,也不存在執(zhí)行程序在函數(shù)的調(diào)用者和函數(shù)之間來(lái)回跳轉(zhuǎn)而引起的時(shí)間和空間的消耗。

通過(guò)上面的程序片段可以很清楚地看到,內(nèi)聯(lián)函數(shù)的定義只需要在函數(shù)聲明或定義的時(shí)候,在前面為其加上inline關(guān)鍵字即可,即

inline返回類(lèi)型函數(shù)名(參數(shù)列表){ …}

在定義內(nèi)聯(lián)函數(shù)時(shí)要注意,在聲明函數(shù)為內(nèi)聯(lián)函數(shù)時(shí),必須同時(shí)定義該函數(shù)的函數(shù)體,如果將聲明和函數(shù)體的定義分開(kāi),那么即使在聲明時(shí)加上了inline關(guān)鍵字,編譯器也只是將該函數(shù)當(dāng)作普通函數(shù)一樣對(duì)待。例如,如下的函數(shù)聲明中,inline關(guān)鍵字是不會(huì)起任何作用的:

inlinestringfunction(inta);

當(dāng)某個(gè)函數(shù)加上inline關(guān)鍵字聲明為內(nèi)聯(lián)函數(shù)以后,在程序的其他地方對(duì)該函數(shù)的調(diào)用就不像一般的函數(shù)是在函數(shù)運(yùn)行時(shí)調(diào)用,而是通過(guò)編譯器在編譯期間就已經(jīng)對(duì)該函數(shù)的調(diào)用處運(yùn)用了代碼的替換。不過(guò)要注意的是,內(nèi)聯(lián)函數(shù)必須在其第一次被調(diào)用前就定義或聲明。另外,inline關(guān)鍵字的使用并不是沒(méi)有限制的,由于編譯器對(duì)內(nèi)聯(lián)函數(shù)的處理是對(duì)其在調(diào)用時(shí)實(shí)行代碼的替換,那么就要求內(nèi)聯(lián)函數(shù)的函數(shù)體內(nèi)的代碼是簡(jiǎn)單結(jié)構(gòu)的,不能有復(fù)雜的結(jié)構(gòu)控制語(yǔ)句或循環(huán)語(yǔ)句,如switch、for等。比如在前面所舉的例子,主函數(shù)在for循環(huán)中調(diào)用內(nèi)聯(lián)函數(shù),如果內(nèi)聯(lián)函數(shù)中有更加復(fù)雜的循環(huán)語(yǔ)句,那么在執(zhí)行代碼的替換后,很可能就會(huì)造成循環(huán)結(jié)構(gòu)的混亂,從而導(dǎo)致程序的錯(cuò)誤。而且內(nèi)聯(lián)函數(shù)本身不能是直接遞歸函數(shù),這樣,也會(huì)由于函數(shù)體內(nèi)的遞歸關(guān)系導(dǎo)致程序結(jié)構(gòu)的混亂。既然內(nèi)聯(lián)函數(shù)是由編譯器在編譯期間處理,那么在下一章將要介紹的虛函數(shù)就沒(méi)有辦法被編譯器當(dāng)作內(nèi)聯(lián)函數(shù)了,由于多態(tài)中虛函數(shù)的特性,要等到程序運(yùn)行時(shí)才知道到底執(zhí)行哪一個(gè)函數(shù)。實(shí)際上,內(nèi)聯(lián)函數(shù)所帶來(lái)的并不僅僅是節(jié)省函數(shù)調(diào)用對(duì)棧空間等的開(kāi)銷(xiāo),而且會(huì)對(duì)編譯器有一定的優(yōu)化作用。因?yàn)楫?dāng)編譯器在編譯一段連續(xù)的且沒(méi)有對(duì)其他函數(shù)調(diào)用的代碼時(shí),會(huì)大大地提高效率,所以當(dāng)使用inline關(guān)鍵字修飾一個(gè)函數(shù)使其成為內(nèi)聯(lián)函數(shù)時(shí),就可以使得編譯器在對(duì)這些連續(xù)的無(wú)函數(shù)調(diào)用的代碼進(jìn)行編譯時(shí)帶來(lái)特殊的優(yōu)化。

如果某個(gè)被inline修飾的函數(shù)的函數(shù)體很小,那么為這個(gè)內(nèi)聯(lián)函數(shù)的函數(shù)體生成的目標(biāo)代碼可能比在調(diào)用一個(gè)函數(shù)時(shí)產(chǎn)生的目標(biāo)代碼要小很多。此時(shí),使用內(nèi)聯(lián)函數(shù)多所帶來(lái)的結(jié)果就是使得目標(biāo)代碼更小,而且對(duì)指令的緩存有更高的使用率。

inline關(guān)鍵字對(duì)于編譯器來(lái)說(shuō),其實(shí)只能算是一種建議,而不是對(duì)編譯器的命令。這個(gè)建議可以用inline關(guān)鍵字顯式或隱式地向編譯器提出。這里所說(shuō)的“隱式”,其實(shí)是對(duì)于類(lèi)的成員函數(shù)而言的,因?yàn)轭?lèi)的成員函數(shù)都被編譯器默認(rèn)為內(nèi)聯(lián)函數(shù)。當(dāng)然,和前面所提到的關(guān)于inline關(guān)鍵字的使用限制一樣,只有當(dāng)成員函數(shù)的函數(shù)體沒(méi)有復(fù)雜的結(jié)構(gòu)時(shí),成員函數(shù)才能被編譯器當(dāng)作內(nèi)聯(lián)函數(shù)來(lái)對(duì)待,否則,編譯器將放棄對(duì)成員函數(shù)的內(nèi)聯(lián)方式的使用。

對(duì)于普通的函數(shù)也一樣,當(dāng)函數(shù)的結(jié)構(gòu)體很復(fù)雜時(shí),即使使用inline關(guān)鍵字進(jìn)行了修飾,在編譯時(shí)編譯器還是會(huì)放棄內(nèi)聯(lián)的方式。在這里,對(duì)前面的一個(gè)知識(shí)點(diǎn)進(jìn)行一些補(bǔ)充。編譯器是否接受inline關(guān)鍵字的請(qǐng)求,并不僅僅取決于函數(shù)體內(nèi)的結(jié)構(gòu)是否復(fù)雜。因?yàn)閮?nèi)聯(lián)函數(shù)并不是完美無(wú)瑕的,它的使用也是有一定的代價(jià)的。由于內(nèi)聯(lián)函數(shù)實(shí)現(xiàn)的本質(zhì)就是在調(diào)用時(shí)實(shí)行代碼的替換,那么這肯定會(huì)增加整個(gè)工程的目標(biāo)代碼的數(shù)量,因此在程序中過(guò)多地使用內(nèi)聯(lián)函數(shù)就會(huì)導(dǎo)致程序的目標(biāo)代碼的龐大,從而導(dǎo)致資源有限的計(jì)算機(jī)的執(zhí)行效率的下降,這樣內(nèi)聯(lián)函數(shù)本來(lái)想體現(xiàn)的優(yōu)勢(shì)將不復(fù)存在,甚至還不如普通函數(shù)的調(diào)用。所以,當(dāng)函數(shù)用inline關(guān)鍵字向編譯器提出請(qǐng)求時(shí),編譯器會(huì)根據(jù)函數(shù)的具體情況來(lái)決定會(huì)不會(huì)對(duì)該函數(shù)真正使用內(nèi)聯(lián)的方式在編譯時(shí)對(duì)其進(jìn)行處理。因此,從這個(gè)角度來(lái)說(shuō),inline關(guān)鍵字對(duì)于編譯器僅僅是個(gè)請(qǐng)求。既然編譯器對(duì)內(nèi)聯(lián)函數(shù)的操作僅僅是代碼的替換,而#define這種宏定義的方式也是替換,那么它們之間又有什么區(qū)別呢?其實(shí),在很多時(shí)候使用宏來(lái)進(jìn)行代碼的替換,也是為了節(jié)省一些系統(tǒng)資源的開(kāi)銷(xiāo)。例如,可以通過(guò)下面的宏定義來(lái)獲得a和b中較大的一個(gè),而不需要再去定義一個(gè)函數(shù):

#defineMAX(a,b)((a)>(b))?(a):(b)

但是宏的使用的局限性太大,比如在前面也提到了,對(duì)于常量建議用const關(guān)鍵字而不使用#define的形式,其原因就是宏的使用沒(méi)有對(duì)數(shù)據(jù)類(lèi)型的檢查。你很難想象,對(duì)于一個(gè)函數(shù)來(lái)說(shuō),內(nèi)部的數(shù)據(jù)如果沒(méi)有數(shù)據(jù)類(lèi)型會(huì)是什么樣子。內(nèi)聯(lián)函數(shù)和宏定義最根本的區(qū)別是:內(nèi)聯(lián)函數(shù)的調(diào)用是由編譯器在編譯期間進(jìn)行函數(shù)體代碼的替換,而宏則是由預(yù)處理器在編譯之前進(jìn)行宏體對(duì)宏名的替換。下面總結(jié)一下宏定義和內(nèi)聯(lián)函數(shù)在代碼替換方面的區(qū)別:

(1)宏的替換方式是在編譯之前由預(yù)處理器進(jìn)行的,即先用宏體替換宏名,然后再進(jìn)行編譯,而內(nèi)聯(lián)函數(shù)的替換方式是在編譯時(shí)由編譯器將函數(shù)體替換為調(diào)用表達(dá)式。(2)由于在宏的定義中是沒(méi)有數(shù)據(jù)類(lèi)型的,因此宏所做的替換其實(shí)只是簡(jiǎn)單的字符串替換,而在對(duì)內(nèi)聯(lián)函數(shù)的調(diào)用中,對(duì)于在代碼替換過(guò)程中的參數(shù)是有數(shù)據(jù)類(lèi)型限制的。

(3)在宏的定義中所使用的參數(shù)不占系統(tǒng)的內(nèi)存空間,只是做簡(jiǎn)單的字符串替換,而在對(duì)內(nèi)聯(lián)函數(shù)的調(diào)用中,參數(shù)的傳遞則是具體變量之間的內(nèi)容傳遞,而且形參會(huì)作為代碼替代后函數(shù)的局部變量,顯然是要占系統(tǒng)的內(nèi)存空間的。因此,內(nèi)聯(lián)函數(shù)不僅能起到宏定義一樣的替換作用,節(jié)省函數(shù)在調(diào)用期間對(duì)系統(tǒng)資源的開(kāi)銷(xiāo),而且解決了在宏的定義中沒(méi)有數(shù)據(jù)類(lèi)型的不足,比宏的使用更加靈活。7.3.2inline函數(shù)與程序效率在前一節(jié)已經(jīng)介紹過(guò),C++引入內(nèi)聯(lián)函數(shù)的目的就是希望解決程序中由于函數(shù)調(diào)用而引起的效率問(wèn)題,所以?xún)?nèi)聯(lián)函數(shù)的使用能夠提高函數(shù)的運(yùn)行效率。內(nèi)聯(lián)函數(shù)的調(diào)用方法和普通函數(shù)一樣,但是由于在編譯期間,編譯器已將內(nèi)聯(lián)函數(shù)的函數(shù)體完全替代了程序中對(duì)內(nèi)聯(lián)函數(shù)的調(diào)用,因此內(nèi)聯(lián)函數(shù)的執(zhí)行效率比一般的函數(shù)要高。在前面已經(jīng)介紹,被inline關(guān)鍵字修飾的內(nèi)聯(lián)函數(shù)不需要再像普通的函數(shù)被調(diào)用一樣,使程序的執(zhí)行權(quán)在函數(shù)的內(nèi)部和函數(shù)被調(diào)用的地方來(lái)回跳轉(zhuǎn),在時(shí)間和空間上都大大提高了效率,而且不需要再為函數(shù)的局部變量在棧中反復(fù)開(kāi)辟內(nèi)存空間了。

一般來(lái)說(shuō),類(lèi)中的成員函數(shù)都會(huì)被編譯器當(dāng)作內(nèi)聯(lián)函數(shù)來(lái)對(duì)待,而最常用的情況莫過(guò)于在類(lèi)中將關(guān)于類(lèi)成員存取的函數(shù)作為內(nèi)聯(lián)函數(shù)來(lái)使用。因?yàn)樵诔绦騿T自定義的類(lèi)中,經(jīng)常會(huì)有很多私有的或者是受保護(hù)的數(shù)據(jù)成員,以防止外界訪(fǎng)

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論