P05面向?qū)ο笤O(shè)計(jì)思想_第1頁(yè)
P05面向?qū)ο笤O(shè)計(jì)思想_第2頁(yè)
P05面向?qū)ο笤O(shè)計(jì)思想_第3頁(yè)
P05面向?qū)ο笤O(shè)計(jì)思想_第4頁(yè)
P05面向?qū)ο笤O(shè)計(jì)思想_第5頁(yè)
已閱讀5頁(yè),還剩78頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

面向?qū)ο蟪绦蛟O(shè)計(jì)江漢大學(xué)數(shù)學(xué)與計(jì)算機(jī)科學(xué)學(xué)院韓海程序設(shè)計(jì)思想1主要的程序設(shè)計(jì)理念運(yùn)算符重載——針對(duì)對(duì)象實(shí)現(xiàn)類似于原運(yùn)算符的功能繼承與組合——如何利用已有的類建立更復(fù)雜的對(duì)象虛函數(shù)——指針指向類族中的哪個(gè)對(duì)象,就調(diào)用該對(duì)象相應(yīng)的方法成員抽象類——類中只規(guī)定有哪些行為,但并不具體實(shí)現(xiàn)多態(tài)——讓同一種行為應(yīng)用于各種對(duì)象、各種情況模板——提高編碼的效率異常處理——設(shè)置錯(cuò)誤處理代碼,應(yīng)對(duì)可能出現(xiàn)的錯(cuò)誤const——保護(hù)數(shù)據(jù),防止被意外破壞流——把不同類型的信息視為一個(gè)數(shù)據(jù)序列泛型——忽略數(shù)據(jù)元素在存儲(chǔ)上的差異,強(qiáng)調(diào)行為上的共性,強(qiáng)化代碼的通用性2類是規(guī)定行為的集合 基本類型 自定義類集合示例 int

CMyEmployee元素示例 15 2010053134,張三,男,1982.3.5.

運(yùn)算 算術(shù)運(yùn)算 規(guī)定的行為(方法)

類是基本數(shù)據(jù)類型的擴(kuò)展,兩者的核心都是集合及集合上的運(yùn)算,基本類型的運(yùn)算表現(xiàn)為“+”、“-”、“*”、“/”等算術(shù)運(yùn)算,是固有運(yùn)算,可直接使用。定義類中包含哪些數(shù)據(jù)元素相對(duì)簡(jiǎn)單。類的核心問題是定義類的方法成員,通過(guò)方法成員表現(xiàn)出類的元素(對(duì)象)具有哪些行為。3對(duì)象的屬性與操作對(duì)象的行為通??梢苑譃橛?jì)算類和非計(jì)算類。非計(jì)算類包括顯示、存儲(chǔ)、傳輸?shù)刃袨?,比如關(guān)于圖形處理建立的區(qū)域類族大體上會(huì)有三角形、方形、多邊形等自定義類,各個(gè)對(duì)象都有在屏幕上畫出該形狀這一行為,而且通常都用同一個(gè)成員名來(lái)描述這個(gè)行為,如“對(duì)象.Draw()”。這一現(xiàn)象將在下一節(jié)“抽象類”當(dāng)中討論。

計(jì)算類行為是指獲取對(duì)象的相關(guān)信息,或者通過(guò)對(duì)象及其它數(shù)據(jù)計(jì)算得到一些信息。比如上述關(guān)于區(qū)域的類族,各個(gè)對(duì)象通常都需要對(duì)外公布(允許外部訪問,public)寬度和高度兩個(gè)數(shù)據(jù),這樣的信息稱為“對(duì)象的屬性”,通常也有相對(duì)固定的成員名,例如取對(duì)象的寬度通常寫作“對(duì)象.GetWidth()”。這一類行為當(dāng)中包含運(yùn)算符重載。4為什么要有運(yùn)算符重載?起因(在上一單元已述,重現(xiàn)):

(1)常規(guī)的運(yùn)算符只運(yùn)用于基本數(shù)據(jù)類型,并且有固定的用法,基本上與數(shù)學(xué)上的用法一致。——好記

(2)類是數(shù)據(jù)與處理(稱為“方法”)的結(jié)合體,有很多處理與常規(guī)的運(yùn)算有直接聯(lián)系,或者是常規(guī)運(yùn)算在意思上的延伸,比如CString類的加法延伸為拼接。

——好理解

(3)設(shè)計(jì)一個(gè)用于實(shí)現(xiàn)加法的函數(shù)Add,帶有兩個(gè)入口參數(shù)分別記作a和b,則調(diào)用該函數(shù)寫作“Add(a,b)”,這一寫法當(dāng)然不如“a+b”更簡(jiǎn)潔易懂?!脤懩繕?biāo):

希望為類設(shè)計(jì)一個(gè)與常規(guī)運(yùn)算符在意義上接近的處理或者計(jì)算,并且沿用常規(guī)運(yùn)算符原有的寫法5運(yùn)算符重載方式重載方式用成員函數(shù)重載用友元函數(shù)重載 特 點(diǎn)“=”等少量的幾個(gè)運(yùn)算符必須用成員函數(shù)的方式重載重載二元運(yùn)算符時(shí),右側(cè)的操作數(shù)可以是各種類型,但左側(cè)的操作數(shù)必須是類的對(duì)象成員函數(shù)的形參數(shù)目等于運(yùn)算符操作數(shù)的數(shù)量減1(1)通常用全局函數(shù)實(shí)現(xiàn)(2)需要訪問類的私有成員時(shí)才需要定義成友元函數(shù)6不能重載的運(yùn)算符 以下運(yùn)算符不能被重載:

成員訪問

.

域限制符 ::

條件運(yùn)算 ?: 取字節(jié)數(shù) sizeof7經(jīng)常被重載的運(yùn)算符運(yùn)算符 分類 重載方式+,-,*,/,% 算術(shù)運(yùn)算 兩種均可>,>=,<,<=,==,!= 關(guān)系運(yùn)算 兩種均可= 賦值 成員函數(shù)+=,-=,*=等 復(fù)合賦值 兩種均可,建議成員函數(shù)++,-- 自增自減 兩種均可,建議成員函數(shù)[],-> 下標(biāo),指向 成員函數(shù)<<,>> 移位/流 兩種均可new與delete 內(nèi)存管理 兩種均可特別地,C++規(guī)定圓括號(hào)“()”也可以重載已述,本節(jié)將只講解++、[]和()這幾個(gè)運(yùn)算符的重載8為CClock類定義前置“++”前述CClock類的聲明如下:classCClock

{public:

CClock(int

h,int

m,ints);

~CClock();

int

GetHour(); //取小時(shí)數(shù)

int

GetMinit(); //取分鐘數(shù)

CString

GetTime(); //取當(dāng)前時(shí)間字符串

voidStepup(); //令時(shí)鐘走一步(1秒)

CClockoperator++();private:

int

m_hour,m_minit,m_second;//時(shí)分秒};CClock類的對(duì)象是時(shí)鐘,“++”的功能顯而易見。用成員函數(shù)為CClock類定義前置“++”,首先需要在類中添加相應(yīng)的函數(shù)聲明。注意,類中已有Stepup函數(shù)可以利用9編寫“operator++”利用已有的Stepup函數(shù),前置自增功能很容易實(shí)現(xiàn):CClock

CClock::operator++(){ Stepup(); return*this;}C++以“是否有形參”來(lái)區(qū)分前置自增和后置自增,后置自增的重載函數(shù)如下:CClock

CClock::operator++(int){ CClockx(*this); //創(chuàng)建臨時(shí)對(duì)象

Stepup(); //即this->Stepup() returnx;}注意:(1)后置自增函數(shù)帶有一個(gè)int型形參,這是區(qū)分前置后置的標(biāo)記,并無(wú)其它含義,函數(shù)體內(nèi)也不使用該參數(shù)值,甚至可以沒有形參的名字;(2)不要忘記在類中添加相應(yīng)的函數(shù)聲明10友元函數(shù)定義前置“++”CClock類的聲明如下:classCClock

{public:

CClock(int

h,int

m,ints);

~CClock();

int

GetHour(); //取小時(shí)數(shù)

int

GetMinit(); //取分鐘數(shù)

CString

GetTime(); //取當(dāng)前時(shí)間字符串

voidStepup(); //令時(shí)鐘走一步(1秒)

friendCClock

operator++(CClock&x);private:

int

m_hour,m_minit,m_second;//時(shí)分秒};CClock

operator++(CClock

&x){

c.Stepup(); returnx;}11友元函數(shù)定義前置“++”這是前置自增的友元函數(shù)聲明:

friendCClock

operator++(CClock

&x);后置自增的友元函數(shù)聲明為:

friendCClock

operator++(CClock

&x,int);相應(yīng)的函數(shù)代碼:CClock

operator++(CClock

&x,int){

CClock

m(x);//記得嗎,這將調(diào)用拷貝構(gòu)造函數(shù)

c.Stepup(); returnm;}最初編寫代碼的時(shí)候忘記了引用,沒有引用是不行的12為CClock定義下標(biāo)[]設(shè)x是CClock類的對(duì)象,即一個(gè)時(shí)鐘,原本x[?]是沒有意義的,但不妨人為地做如下定義:

x[0]---時(shí)鐘的當(dāng)前小時(shí)數(shù)

x[1]---時(shí)鐘的當(dāng)前分鐘數(shù)

x[2]---時(shí)鐘的當(dāng)前秒數(shù)

x[i]----1,i不是0、1、2時(shí)根據(jù)運(yùn)算符重載的有關(guān)規(guī)則,下標(biāo)運(yùn)算“[]”必須用成員函數(shù)實(shí)現(xiàn),則在寫法上“x[i]”是函數(shù)調(diào)用“x.operator[](i)”的變形,“k=x[i]”也可以寫成:

k=x.operator[](i)13為CClock類定義“[]”在CClock類中添加關(guān)于[]的成員函數(shù)如下:classCClock{public:

CClock(int

h,int

m,ints);

~CClock();

int

GetHour(); //取小時(shí)數(shù)

int

GetMinit(); //取分鐘數(shù)

CString

GetTime(); //取當(dāng)前時(shí)間字符串

voidStepup(); //令時(shí)鐘走一步(1秒)

CClockoperator[]();private:

int

m_hour,m_minit,m_second;//時(shí)分秒};14CClock類的“operator[]”int

CClock::operator[](inti){

if(i==0) returnm_hour;

if(i==1) returnm_minit;

if(i==2) returnm_second; return-1;};15重載“[]”的意義設(shè)x是一個(gè)對(duì)象,通過(guò)運(yùn)算符重載,可以把原本沒有意義的寫法“x[?]”賦予確定的含義,這與前述的運(yùn)算符重載有著重大差異。

既然如此,對(duì)于任意一個(gè)允許重載的運(yùn)算符,也可以賦予它與原運(yùn)算符完全沒有關(guān)聯(lián)的功能。但是極少有人這樣用,因?yàn)檫\(yùn)算符重載的目的在于借用運(yùn)算符原有的含義、用原有的寫法實(shí)現(xiàn)對(duì)象的某些處理功能,如果這些功能與被重載的運(yùn)算符相去甚遠(yuǎn),則重載的效果只會(huì)讓人造成概念上的混亂,不利于軟件開發(fā)。正如在定義一個(gè)函數(shù)時(shí),通常都以與函數(shù)功能相關(guān)的英文單詞或者編寫作為函數(shù)名。16CClock類的“operator()”對(duì)于對(duì)象x,運(yùn)算符重賦予了“x[?]”一定的意義,對(duì)于同樣原本沒有意義的“x(?)”也可以依照此例處理。實(shí)際上,把對(duì)“[]”重載時(shí)所有的“[”換成“(”、所有的“]”換成“)”,前述代碼同樣可以編譯通過(guò)。很多資料上把“operator()”稱為函數(shù)調(diào)用運(yùn)算符,這容易在概念上造成混亂。建議:不用管它叫什么名字,因?yàn)閷?duì)于對(duì)象x而言,“x(?)”原本沒有意義,現(xiàn)在通過(guò)運(yùn)算符重載規(guī)定了該寫法的含義。17繼承還是組合面向?qū)ο蟪绦蛟O(shè)計(jì)的基本設(shè)計(jì)單位是“類”,類的本質(zhì)是規(guī)定了對(duì)象的數(shù)據(jù)信息和行為。設(shè)計(jì)更復(fù)雜的程序時(shí),可以利用已有的類,在利用方法上就有了本頁(yè)的標(biāo)題:繼承還是組合?——本節(jié)只考慮public繼承設(shè)X和Y是兩個(gè)類,x是X的對(duì)象,y是Y的對(duì)象繼承(“isa”關(guān)系)——如果X是Y的派生類,則:

xisay. (見下頁(yè)圖元類族示例)組合(“hasa”關(guān)系)——如果y是x的一個(gè)子對(duì)象,則:

xhasay.例如:CMyEmployee類中包含兩個(gè)CString子對(duì)象,

Theemployeehasanumber. Theemployeehasaname.18繼承描述“isa”關(guān)系Point(點(diǎn))isaelement(圖元)Rigion(區(qū)域)isaelement(圖元)Circle(方形)isaRigion(區(qū)域)...... 圖元顏色,尺寸,邊界畫圖,擦除,取邊界點(diǎn)線起點(diǎn),終點(diǎn),線型區(qū)域填充模式,透明度直線弧線......曲線......方形......圓形......多邊形......注意,不論是繼承還是組合,在x中都包含一個(gè)y的對(duì)象作為x的一部分!繼承與組合到底有什么差別?19繼承與組合的差異xisay(繼承)(1)編寫X類的成員函數(shù)代碼時(shí),可以訪問y的public成員和protected成員,包括方法成員也包括數(shù)據(jù)成員(2)在類的外部編寫代碼時(shí),可以訪問x的public成員,也能訪問y的public成員(3)CX的構(gòu)造函數(shù)以“:CY(...)”指明如何調(diào)用基類的構(gòu)造函數(shù)xhasay(組合)(1)編寫X類的成員函數(shù)代碼時(shí),只能訪問y的public成員,包括方法成員和數(shù)據(jù)成員(2)在類的外部編寫代碼時(shí),只能訪問x的public成員(3)CX的構(gòu)造函數(shù)以“:子對(duì)象名(...)”指明如何調(diào)用子對(duì)象的構(gòu)造函數(shù)20測(cè)試1,派生類內(nèi)部CY類的聲明:classCY{public:f1();

intd1;protected:f2();

intd2;private:f3();

intd3;}CX類的聲明:classCX:publicCY//繼承{public:f_x1();

intd_x1;protected:f_x2();

intd_x2;private:f_x3();

intd_x3;}編寫CX的函數(shù)代碼時(shí),允許訪問CX和CY的哪些成員?21測(cè)試2,派生類外部CY類的聲明:classCY{public:f1();

intd1;protected:f2();

intd2;private:f3();

intd3;}CX類的聲明:classCX:publicCY//繼承{public:f_x1();

intd_x1;protected:f_x2();

intd_x2;private:f_x3();

intd_x3;}x是CX的對(duì)象,“x.?”是合法的訪問?22測(cè)試3,組合類內(nèi)部CY類的聲明:classCY{public:f1();

intd1;protected:f2();

intd2;private:f3();

intd3;}編寫CX的函數(shù)代碼時(shí),允許訪問CX和CY的哪些成員?CX類的聲明:classCX //組合{public:f_x1();CYy1;protected:f_x2();CYy2;private:f_x3();CYy3;}訪問CY的成員時(shí),必須指明訪問哪一個(gè)子對(duì)象的成員,比如“y1.f1()”、“y2.f1()”、“y3.d1=5”23測(cè)試4,組合類外部CY類的聲明:classCY{public:f1();

intd1;protected:f2();

intd2;private:f3();

intd3;}CX類的聲明:classCX //組合{public:f_x1();CYy1;protected:f_x2();CYy2;private:f_x3();CYy3;}x是CX的對(duì)象,“x.?”是合法的訪問?x.f_x1() x.y1.f1() x.y1.d1=5;24多用組合少用繼承如本頁(yè)標(biāo)題所示,在建立新的類時(shí),多用組合少用繼承。并且把子對(duì)象置于private保護(hù)之下。原因:面向?qū)ο蟮暮诵乃枷胫皇欠庋b,即允許外部訪問對(duì)象的哪些成員。以繼承的方式建立新的類,編寫代碼的人往往容易忽略可以從外部訪問基類的public成員,從而導(dǎo)致一些預(yù)料之外的信息暴露。當(dāng)然,最根本的還是根據(jù)“isa”還是“hasa”關(guān)系來(lái)選用繼承和組合。25繼承導(dǎo)致類族轉(zhuǎn)換話題:面向?qū)ο蟮某绦蛟O(shè)計(jì)模式中經(jīng)常會(huì)設(shè)計(jì)一系列有繼承與派生關(guān)系的類,從一個(gè)基類開始往下派生出的所有的類形成一個(gè)“類族”。類族的設(shè)計(jì)思想顯然是為了代碼重用。在一個(gè)類族中,對(duì)象盡管屬于不同的類,但通常都有一些相同的特征或者行為。即:類族中任意一個(gè)類的對(duì)象都擁有基類的數(shù)據(jù)成員(雖然有可能因?yàn)槔^承方式而不能訪問),視作具有相同的特征信息;類族中的對(duì)象通常也具有一些同名的函數(shù)成員,視作具有相同的行為,這些函數(shù)的功能相同或相似,但實(shí)現(xiàn)的具體代碼可以不同。26類族對(duì)象的共性例如,以“圖元”為基類的類族具有顏色、尺寸等共同的數(shù)據(jù)成員,以及畫、擦等同名的方法成員;除此之外,以“區(qū)域”為基類的類族還具有填充模式、透明度這兩個(gè)共同的數(shù)據(jù)成員。圖元顏色,尺寸,邊界畫圖,擦除,取邊界點(diǎn)線起點(diǎn),終點(diǎn),線型區(qū)域填充模式,透明度直線弧線......曲線......方形......圓形......多邊形......27對(duì)圖元類族確定名稱為了后續(xù)敘述的方便,為各個(gè)類及各個(gè)成員命名CElementcolor,size,borderDraw,Erase,...CPointCSegmentstart,end,styleCAreapattern,transparencyCLineCArc......CCurve......CSquare......CCircle......CPolygon......28創(chuàng)建對(duì)象與調(diào)用方法設(shè)有如下的創(chuàng)建對(duì)象:

CElementx1; //圖元

CArea x2; //區(qū)域

CSegmentx3; //線

CCirclex4; //圓則,以下調(diào)用非常明確是調(diào)用哪個(gè)對(duì)象的哪個(gè)方法:

x1.Draw(); x2.Draw(); x3.Draw(); x4.Draw();原本沒有疑問的用法會(huì)因?yàn)橹羔樁a(chǎn)生歧義,見下頁(yè)。29重要規(guī)則C++規(guī)定:

派生類的地址可以賦值給指向基類的指針變量你如何理解這個(gè)規(guī)則?請(qǐng)先看下面的例子為了說(shuō)明問題的簡(jiǎn)便,改用下面的最簡(jiǎn)單的類聲明:classCA{public: voidfun() {cout<<"FunofCA\n";};};classCB:publicCA{public: voidfun() {cout<<"FunofCB\n";}; voidfb(){cout<<"Thisisfb\n";};};記住各函數(shù)的顯示效果!30類族中的指針指向指出下面代碼中的錯(cuò)誤:main(){ CAx,*p; CBy,*q; p=&y; q=&x; p->fun(); p->fb(); q->fun();}派生類地址可以賦值給指向基類的指針變量,反之不行這一行是對(duì)的,不用寫“p=(CA*)&y;”p的類型決定了通過(guò)p只能訪問CA的成員,fb是CB的成員但不是CA的成員31指針指向類族中的對(duì)象指出下面代碼中的運(yùn)行結(jié)果:main(){ CAx,*q; CBy;

x.fun(); q=&x; q->fun();

y.fun(); q=&y; q->fun();}最后一行顯示值得探討:q是指向基類CA的指針變量,但此時(shí)指向派生類對(duì)象y,“q->fun()”到底調(diào)用哪個(gè)函數(shù)?另外,編程者希望它調(diào)用哪個(gè)函數(shù)?32再談規(guī)則上述規(guī)則的意義:(1)因?yàn)榇a重用而產(chǎn)生了類族,類族中的對(duì)象都有相同或者相似的行為。在編程者看來(lái),類族中的對(duì)象都是“差不多”的。(2)編程者希望借用一個(gè)指針變量,不論該指針指向類族中的哪一個(gè)對(duì)象,都能正確地訪問相應(yīng)的成員。如果派生類對(duì)基類的某個(gè)方法成員編寫了新代碼(覆蓋),則希望指針指向派生類對(duì)象時(shí),能夠訪問新代碼。(3)以“基類*q”定義指針變量,則通過(guò)q只能訪問基類的成員,而不能訪問派生類新增的成員,從而保證不會(huì)出現(xiàn)訪問一個(gè)不存在的成員的現(xiàn)象。派生類地址可以賦值給指向基類的指針變量,反之不行前述示例說(shuō)明沒能做到這一點(diǎn)33虛函數(shù)虛函數(shù)專門用于解決上述問題:如前例,基類中定義了方法成員fun,派生類更新了該方法。以“CA*q;”定義指針變量,希望當(dāng)q指向基類CA的對(duì)象時(shí),“q->fun()”訪問基類CA的成員函數(shù)fun;當(dāng)q指向派生類CB的對(duì)象時(shí),“q->fun()”訪問派生類CB更新之后的成員函數(shù)fun。簡(jiǎn)言之:希望q指向誰(shuí)就調(diào)用誰(shuí)的成員函數(shù)對(duì)于上述需求,需要在基類中把該方法成員定義成“虛函數(shù)”。聲明虛函數(shù)的格式如下:

virtual

返回值類型函數(shù)名(形參表);34聲明虛函數(shù)下面是定義CA和CB兩個(gè)類,在適當(dāng)?shù)奈恢眉由咸摵瘮?shù)標(biāo)記virtual:classCA{public: voidfun() {cout<<"FunofCA\n";};};classCB:publicCA{public: voidfun() {cout<<"FunofCB\n";}; voidfb(){cout<<"Thisisfb\n";};};virtual35有關(guān)虛函數(shù)的說(shuō)明類的靜態(tài)成員函數(shù)和內(nèi)聯(lián)函數(shù)不能聲明為虛函數(shù)定義成員函數(shù)為虛函數(shù),并不代表該函數(shù)是“虛”的,而是為了通過(guò)指針變量能夠訪問正確的方法成員,通過(guò)對(duì)象名訪問成員與虛函數(shù)無(wú)關(guān)一旦在一個(gè)類中定義了虛函數(shù),則以該類為起點(diǎn)的類族中該函數(shù)都是虛函數(shù),派生類中的相應(yīng)函數(shù)不再需要用virtual說(shuō)明構(gòu)造函數(shù)不能聲明為虛函數(shù),析構(gòu)函數(shù)往往聲明為虛函數(shù)基類中聲明虛函數(shù)時(shí)必須明確形參,派生類中相應(yīng)函數(shù)不僅要同名,也要求形參相同36測(cè)試classCX{public:virtualint

fa();

int

fb();}classCY:publicCX{public:virtualint

fb();}classCZ:publicCY{public:virtualint

fa(intn);

int

fb(intn);}classCW:publicCZ{public:virtualint

fa();

int

fb();}說(shuō)明各個(gè)類的對(duì)象能訪問哪些函數(shù)成員?哪些類的哪些函數(shù)構(gòu)成一組虛函數(shù)畫出層次結(jié)構(gòu)圖37虛函數(shù)的實(shí)現(xiàn)原理面向?qū)ο蟪绦蛟O(shè)計(jì)允許函數(shù)重載(overload)與函數(shù)覆蓋(override),前者導(dǎo)致函數(shù)同名但形參不同,后者則是同名同形參。前面已有若干示例說(shuō)明后者的有關(guān)規(guī)則,核心問題是當(dāng)代碼中出現(xiàn)一個(gè)函數(shù)調(diào)用時(shí),究竟是調(diào)用哪一段具體的函數(shù)代碼。解決問題的方法是對(duì)虛函數(shù)采用動(dòng)態(tài)聯(lián)編方式。動(dòng)態(tài)聯(lián)編——也稱動(dòng)態(tài)綁定,是與靜態(tài)聯(lián)編相對(duì)而言的。當(dāng)類族中含有虛函數(shù)時(shí),為類族的每個(gè)對(duì)象安排虛函數(shù)表(是各個(gè)虛函數(shù)入口地址的列表,與數(shù)據(jù)成員安排在一起)。對(duì)于通過(guò)指向基類的指針訪問函數(shù)成員的情況,編譯時(shí)處理成“從虛函數(shù)表中找函數(shù)的入口地址”。38設(shè)計(jì)圖元類族的方法成員Q:請(qǐng)?jiān)O(shè)計(jì)CElement類的Draw方法的功能及代碼CElementcolor,size,borderDraw,Erase,...CPointCSegmentstart,end,styleCAreapattern,transparencyCLineCArc......CCurve......CSquare......CCircle......CPolygon......Draw的功能好說(shuō),就是在指定位置畫出這個(gè)圖元。代碼沒法寫,因?yàn)樵贑Element類中并不知道圖元的具體情況。如果真的要寫代碼,只能是空代碼,什么也不做!39純虛函數(shù)與抽象類采用繼承與派生的層次式設(shè)計(jì)構(gòu)建一個(gè)類族時(shí),越上層的類就越抽象,越下層的類就越具體。有時(shí)上層的方法根本無(wú)法明確行為,比如“圖元”的Draw

在C++中,允許一個(gè)類只規(guī)定方法成員的首部而不編寫函數(shù)體,這樣的方法稱為“純虛函數(shù)”,含有純虛函數(shù)的類稱為“抽象類”。純虛函數(shù)是在類聲明中用如下形式定義函數(shù)成員:

virtual函數(shù)值類型函數(shù)名(形參表)=0;注意,上述格式中的“=0”表示該函數(shù)是純虛函數(shù)。雖然在語(yǔ)法上virtual不是必須的,但一般只有類族中基類的虛函數(shù)才設(shè)計(jì)成不編寫函數(shù)體。40抽象類的作用抽象類中至少含有一個(gè)純虛函數(shù),試圖調(diào)用純虛函數(shù)將導(dǎo)致沒有相應(yīng)的代碼可以執(zhí)行,所以,不允許創(chuàng)建抽象類的對(duì)象!抽象類的作用表現(xiàn)在規(guī)定由此向下的一個(gè)類族(或者類族分支)中有哪些共同的方法成員,并統(tǒng)一這些方法成員的函數(shù)名稱及參數(shù)形式。比如,關(guān)于“圖元”的類族中,“圖元”定義方法成員“Draw”,“線”定義方法成員“GetLength”,區(qū)域定義方法成員“GetArea”,這些方法都無(wú)法編寫代碼,但在相應(yīng)的類族中有相同的名稱,并且有相同的形參列表。41什么是多態(tài)多態(tài)(Polymorphism)——簡(jiǎn)言之,“一個(gè)接口,多種實(shí)現(xiàn)”接口,是指函數(shù),包括普通函數(shù)和成員函數(shù)一個(gè)接口,是指同名函數(shù),顯然不是一個(gè)函數(shù)而是一組函數(shù)多種實(shí)現(xiàn),是指同一個(gè)函數(shù)名之下有多種不同的代碼以應(yīng)對(duì)不同的參數(shù)、對(duì)象、環(huán)境等因素接口,泛指實(shí)體與外界聯(lián)系的方式、通道。對(duì)象與外界聯(lián)系的方式可以有數(shù)據(jù)成員和函數(shù)成員,但“封裝”導(dǎo)致對(duì)于多數(shù)類而言,外界不能直接訪問對(duì)象的數(shù)據(jù)成員,只能通過(guò)類所提供的方法成員獲取信息,或者令對(duì)象產(chǎn)生相應(yīng)的行為。所以,面向?qū)ο笾械摹敖涌凇蓖ǔV赋蓡T函數(shù)。42多態(tài)的種類有資料把多態(tài)劃分為通用多態(tài)和特定多態(tài),前者包括參數(shù)多態(tài)和包含多態(tài),后者包括重載多態(tài)和強(qiáng)制多態(tài),但這樣的劃分值得商榷,原因見下頁(yè)1.參數(shù)多態(tài)——由函數(shù)模板產(chǎn)生的模板函數(shù)(同名函數(shù)處理不同類型的數(shù)據(jù)),由類模板產(chǎn)生的模板類,除了數(shù)據(jù)類型不同,其它部分相同2.包含多態(tài)——類族中同名成員函數(shù),在指針指向某對(duì)象時(shí),動(dòng)態(tài)綁定相應(yīng)的函數(shù)成員3.重載多態(tài)——函數(shù)重載、運(yùn)算符重載,以同名函數(shù)處理不同數(shù)量、不同類型的數(shù)據(jù)4.強(qiáng)制多態(tài)——某些運(yùn)算符具有自動(dòng)數(shù)據(jù)類型轉(zhuǎn)換功能,如“int+double”時(shí),先把int轉(zhuǎn)換成double,再進(jìn)行加法運(yùn)算多態(tài)的四種形式43歸并一下多態(tài)的種類多態(tài)的作用在于以相同或者相似的形式處理不同類型、不同數(shù)量的數(shù)據(jù),或者處理不同類的對(duì)象。分析前述劃分,可以再歸并一下,得到三個(gè)種類:1.函數(shù)重載(overload),以同一范圍內(nèi)的一組同名函數(shù)應(yīng)對(duì)不同數(shù)量、類型的數(shù)據(jù)2.函數(shù)覆蓋(override),以類族中的同名函數(shù)應(yīng)對(duì)類族中的各個(gè)對(duì)象3.自動(dòng)轉(zhuǎn)換(含運(yùn)算符重載),基本運(yùn)算符應(yīng)對(duì)不同類型的數(shù)據(jù)/對(duì)象只有類模板不在此列。先看看什么是類模板,什么是模板類,似曾相識(shí)的概念。44函數(shù)模板:由template開始編寫的一段函數(shù)定義,表示一組函數(shù),除了類型標(biāo)記不同、其它部分都相同模板函數(shù):由函數(shù)模板生成的函數(shù)函數(shù)模板并不是函數(shù)定義,為什么可以直接調(diào)用? 因?yàn)橛珊瘮?shù)模板可以生成相應(yīng)的函數(shù)定義由誰(shuí)來(lái)生成函數(shù)定義代碼?在什么時(shí)候生成? 編譯器在首次遇到對(duì)模板函數(shù)調(diào)用的時(shí)候生成生成函數(shù)代碼時(shí)其中未定的類型怎么處理? 根據(jù)調(diào)用時(shí)參數(shù)的類型將相應(yīng)的類型標(biāo)識(shí)符代替模板中的類型標(biāo)記復(fù)習(xí):函數(shù)模板與模板函數(shù)函數(shù)模板:模板函數(shù):函數(shù)模板并不是函數(shù)定義,為什么可以直接調(diào)用?由誰(shuí)來(lái)生成函數(shù)定義代碼?在什么時(shí)候生成?生成函數(shù)代碼時(shí)其中未定的類型怎么處理?45類模板:由template開始編寫的一段類聲明(含其中的成員函數(shù)代碼),其中除了含有特定的類型標(biāo)記,表示一組類聲明,除了類型標(biāo)記不同、其它部分都相同模板類:由類模板生成的類類模板并不是類,為什么可以直接定義它的對(duì)象? 因?yàn)橛深惸0蹇梢陨上鄳?yīng)的類定義,即類聲明由誰(shuí)來(lái)生成類聲明的代碼?在什么時(shí)候生成? 編譯器在首次遇到使用模板類的時(shí)候生成生成類聲明的代碼時(shí)其中未定的類型怎么處理? 使用模板類時(shí)需要指明類模板中的類型標(biāo)記用什么具體的類型標(biāo)識(shí)符代替類模板與模板類46一個(gè)簡(jiǎn)單的類模板先來(lái)個(gè)最簡(jiǎn)單的。如果想根據(jù)下面的類來(lái)定義一個(gè)類模板,讓其中的int可以是各種數(shù)據(jù)類型:

classCA { public: CA(int

n){mm=n;}; voidf(){cout<<mm<<endl;};

intmm; };template<typename

T>TTCA<T>如果想在類聲明之后再寫函數(shù)體,怎么辦?47template<typenameT>classCA{public: CA<T>(Tn){mm=n;}; voidf(){cout<<mm<<endl;}; Tmm;};類模板后面寫成員函數(shù)代碼template<typenameT>voidCA<T>::f(){cout<<mm<<endl;}不就是把這個(gè)函數(shù)體移到后面去嗎?;48template<typenameT>classCA{public: CA<T>(Tn){mm=n;}; voidf(); Tmm; //演示!}; template<typenameS>voidCA<S>::f(){ cout<<mm<<endl;}voidmain(){ CA<int>x(3);

x.f(); CA<double>y(4.567);

y.f();}看一看效果49含雙參數(shù)的類模板如果類模板中需要兩個(gè)不同類型的參數(shù),怎么辦?classCA{public:CA(inta,doubleb){mm=a;nn=b;};voidf(){cout<<mm<<','<<nn<<endl;};

intmm;

double

nn;};template<typename

S,typename

T>SSTTCA<S,T>把這個(gè)函數(shù)體移出去也不難;template<typename

S,typenameT>voidCA<S,T>::f(){cout<<mm<<','<<nn<<endl;}50template<typename

S,typename

T>classCA{public: CA<S,T>(Sa,T

b){mm=a;nn=b;}; voidf();private: Smm; Tnn; };template<typename

X,typename

Y>voidCA<X,Y>::f(){ cout<<mm<<'('<<sizeof(mm)<<")\n";

cout<<nn<<'('<<sizeof(nn)<<")\n";}voidmain(){ CA<char,int>t1('1',2); CA<double,int>t2(3.45,6); CA<int,double>t3(7,8.9); t1.f(); t2.f(); t3.f();}再看看效果51類模板只聲明了生成若干個(gè)類的可能性,只有在編譯器遇到對(duì)類的實(shí)際使用時(shí)(比如定義類的對(duì)象),才會(huì)生成相應(yīng)的類——稱為類模板的實(shí)例化類模板實(shí)例化時(shí)必須顯式指明模板所含參數(shù)的類型類模板中除了在class后面首次出現(xiàn)的類名之外,其它用到類名的時(shí)候都要寫“類名<參數(shù)表>”的完整寫法,但構(gòu)造函數(shù)、析構(gòu)函數(shù)則可以省略為只用“類名”在類聲明之后編寫成員函數(shù)代碼時(shí),需要重新寫template及參數(shù),參數(shù)的數(shù)量必須相同,參數(shù)名稱可變,而且類限制符“::”前面的類名必須用完整寫法類模板規(guī)則要點(diǎn)52針對(duì)下面的要求設(shè)計(jì)類模板CArray:能夠存放一批數(shù)據(jù)成員函數(shù)GetData能夠根據(jù)輸入情況確定存放多少個(gè)數(shù)據(jù),并從鍵盤上讀取這一批數(shù)據(jù)成員函數(shù)Display能夠顯示當(dāng)前存放的數(shù)據(jù)成員函數(shù)Sort能夠?qū)Ξ?dāng)前存放的數(shù)據(jù)排序(升序)為了測(cè)試,安排主函數(shù)如下,并要求替換其中的double為int、float、char等常用類型多次測(cè)試

voidmain() {CArray<double>x;

x.GetData();

x.Display();

x.Sort();

x.Display(); }復(fù)雜一點(diǎn)的類模板53template<typenameT>classCArray{public:

CArray(){m_arr=NULL;m_count=0;};

~CArray(){if(m_arr)delete[]m_arr;};

int

GetData(); voidDisplay(); voidSort();private: T*m_arr; //根據(jù)需求申請(qǐng)存儲(chǔ)空間

int

m_count;};定義類模板54template<typenameT>int

CArray<T>::GetData(){ int

i,n;

cout<<"Howmanynumbers:";

cin>>n;

if(n<=0) return0;//沒有數(shù)據(jù)需要存儲(chǔ)

if(m_arr) delete[]m_arr;//刪除原數(shù)據(jù)

m_arr=newT[n];

if(!m_arr) return-1;//申請(qǐng)內(nèi)存失敗

m_count=n;

for(i=0;i<n;i++) { cout<<"X["<<i<<"]=";//操作提示

cin>>m_arr[i]; } returnn;}編寫GetData55template<typenameT>voidCArray<T>::Display(){ inti;

if(m_count<=0)

cout<<"Arrayisempty.\n"; else {cout<<m_count<<"numbersinArray.\n";

for(i=0;i<m_count;i++) { cout.width(8);

cout<<m_arr[i]; }

cout<<"\n\n"; }}編寫Display56template<typenameT>voidCArray<T>::Sort(){ int

i,j; Tt;

for(i=1;i<m_count;i++)

for(j=0;j<m_count-i;j++)

if(m_arr[j]>m_arr[j+1]) { t=m_arr[j];

m_arr[j]=m_arr[j+1]; m_arr[j+1]=t; }}//終于編寫完了,測(cè)試一下吧編寫Sort57高手編的軟件不會(huì)死下面是一個(gè)常見現(xiàn)象:通常,要么等待數(shù)秒之后軟件被關(guān)閉,要么就這么一直等下去。如何看待這一現(xiàn)象?58軟件中的BUG什么原因造成了軟件崩潰?

(1)非法命令 (2)錯(cuò)誤的語(yǔ)序例,指出以下代碼中存在的問題或者錯(cuò)誤:voidmain(){int

i,n;double*x;x=newdouble[n];

cin>>n;

for(i=n;i>0;i--){ x[i]=i/(i-1); out<<i<<','<<x[i]<<endl;}}有借無(wú)還對(duì)不存在的變量賦值除以0次序錯(cuò)誤還有兩個(gè)可能的問題:輸入到n的值不合適,比如負(fù)數(shù);用new申請(qǐng)內(nèi)存空間可能失敗59錯(cuò)誤種類這里的“非法命令”不是指語(yǔ)法錯(cuò)誤(語(yǔ)法錯(cuò)誤由編譯器處理),而是指命令計(jì)算機(jī)執(zhí)行一個(gè)不正確的操作,包括以下幾種情況:非法訪問內(nèi)存。比如前例中對(duì)x[n]賦值非法操作。比如前例中可能存在的除以0非法訪問硬件。連接到計(jì)算機(jī)的各種設(shè)備各有各的使用特點(diǎn),有些只讀,有些只寫,有些要求先做A再做B,等等“非法語(yǔ)序”往往會(huì)造成變量中存儲(chǔ)的數(shù)據(jù)不正確,從而使得后續(xù)語(yǔ)句達(dá)不到預(yù)期的執(zhí)行效果60處理可能的錯(cuò)誤代碼中不允許出現(xiàn)語(yǔ)法錯(cuò)誤和邏輯錯(cuò)誤,比如前例中對(duì)x[n]賦值,這是編碼、調(diào)試、測(cè)試階段必須解決的對(duì)可能出現(xiàn)問題的命令要有應(yīng)對(duì)措施,例如:

cin>>n;

if(n<MIN||n>MAX)cout<<"..."; else {x=newdouble[n];

if(x==NULL)cout<<"..."; else

for(i=n-1;i>=0;i--) {x[i]=...; out<<i<<','<<x[i]<<endl; } }61函數(shù)調(diào)用造成的困難func_A(){......}func_B(){......

func_A();......}func_C(){......

func_B();......}main(){......

func_C();......}一旦最底層函數(shù)調(diào)用時(shí)出了問題,比如問題在func_A中,通常需要以函數(shù)值的方式逐層“上報(bào)”,在某一層決定最終如何處理這個(gè)問題62異常處理機(jī)制出現(xiàn)問題逐級(jí)上報(bào)的處理方法代碼較大,異常處理機(jī)制是解決該問題的另一種思路:不論哪一級(jí)出現(xiàn)問題,只需要“報(bào)告一下”(不一定是對(duì)直接上級(jí)),稱為“拋出異常”。在某個(gè)函數(shù)中設(shè)置一段代碼來(lái)統(tǒng)一處理這些報(bào)告。統(tǒng)一處理異常由try和一組catch構(gòu)成,格式見下頁(yè);拋出異常則相對(duì)簡(jiǎn)單:

throw(參數(shù));其中,表示異常情況的參數(shù)可以是任何類型的數(shù)據(jù),也可以是某個(gè)類的對(duì)象,用途是向處理機(jī)制報(bào)告出現(xiàn)了什么樣的異常。63處理異常的編寫格式處理異常的代碼部分由兩段構(gòu)成:try{可能拋出異常的代碼}catch(形參A){處理A}catch(形參B){處理B}catch(形參C){處理C}......這一段可能有問題,沒關(guān)系,做就是了,有問題就報(bào)告根據(jù)不同的錯(cuò)誤報(bào)告采取相應(yīng)的處理措施工作方式:在執(zhí)行try后面的代碼的過(guò)程中,只要有異常拋出,立即轉(zhuǎn)到catch部分,根據(jù)拋出的異常的類型執(zhí)行對(duì)應(yīng)的處理代碼,如果沒有對(duì)應(yīng)的代碼則產(chǎn)生運(yùn)行錯(cuò)誤。處理結(jié)束后執(zhí)行catch后面的語(yǔ)句64仍然可能造成軟件崩潰voidfunca(){intn;

cout<<"InputinA:";

cin>>n;

if(n<0)throw("A");}voidfuncb(){doublex;

funca();

cout<<"InputinB:";

cin>>x;

if(x<0)throw(x);elseif(x==0)

throw("B");

funca();}voidmain(){try{ funcb(); }

catch(char*x){cout<<x<<endl;}

catch(intx){ cout<<"x="<<x<<endl;}

cout<<"==========\n";}看看以上代碼在輸入不同的數(shù)據(jù)時(shí)的運(yùn)行結(jié)果65異常處理不是萬(wàn)能的異常處理機(jī)制僅僅是把編寫代碼時(shí)在各個(gè)函數(shù)中對(duì)出現(xiàn)的問題進(jìn)行處理改為在一個(gè)函數(shù)中統(tǒng)一處理,如果代碼中出現(xiàn)非法訪問內(nèi)存、除以0等現(xiàn)象仍將導(dǎo)致軟件崩潰,另一種導(dǎo)致崩潰的原因是對(duì)拋出的異常沒有安排相應(yīng)的處理代碼。66防止意外修改數(shù)據(jù)被意外修改是另一個(gè)安全隱患。以編寫函數(shù)為例,為了減少參數(shù)傳遞的開銷,有時(shí)以引用作為形參,但這樣做的后果是函數(shù)內(nèi)部對(duì)形參的修改將直接導(dǎo)致實(shí)際數(shù)據(jù)的改變。例如:doublefunc(double

&x){if(x>0) x=(int)(x*100+0.5)*0.01;else x=(int)(x*100-0.5)*0.01;returnx;}沒有“&”是常規(guī)用法。如果用引用作為形參,在完成求值計(jì)算的同時(shí)會(huì)改變實(shí)際參數(shù)的值。這樣的修改往往并非有意為之,而是一種疏忽。67const有關(guān)規(guī)則A用const可以限制數(shù)據(jù)被修改,前述“常變量”是const的最初應(yīng)用。const的主要用法:(1)定義普通變量,限定不允許改變變量的值,即前述“常變量”:

const類型變量名=初值;或者 類型const變量名=初值;(2)定義普通對(duì)象,限定不允許訪問對(duì)象的任何成員,不論是public、protected還是private:

const類對(duì)象名(初值);或者 類const對(duì)象名(初值);如此定義的對(duì)象又稱“常對(duì)象”,用作初始化其它對(duì)象、給其它對(duì)象賦值等68const有關(guān)規(guī)則B(3)const用于定義指針變量時(shí)有所不同:① const類型*變量名=初值;不允許改變指針?biāo)缸兞康闹?,如果指針指向?qū)ο螅膊辉试S訪問對(duì)象的任何成員,但可以令指針變量指向其它位置② 類型*const變量名=初值;不允許改變指針變量所指位置,但可以改變指針?biāo)缸兞康闹担绻羔樦赶驅(qū)ο?,允許訪問對(duì)象的public成員③ const

類型*const變量名=初值;兩者都不允許69const有關(guān)規(guī)則C(4)const用于定義引用:

const類型&引用名=目標(biāo);不允許通過(guò)引用改變目標(biāo)的值,如果是對(duì)象的引用,也不允許通過(guò)引用訪問對(duì)象的任何成員(5)const用于函數(shù)形參這種用法除了是在參數(shù)傳遞時(shí)確定初值之外,與前述相應(yīng)各種情況的規(guī)則對(duì)應(yīng)相同70什么是“流”這里所說(shuō)的“流”是以字節(jié)為單位進(jìn)行串行數(shù)據(jù)傳輸?shù)男问?。?jì)算機(jī)中還有一種是以“位”為單位的流,稱“比特流”。對(duì)于一般的傳輸,總是需要有建立連接、傳輸、撤除連接三個(gè)步驟,這里的“流”加上一個(gè)特點(diǎn):?jiǎn)蜗?。?duì)于面向?qū)ο蟮木幊潭?,最常見的“流”是文件和?biāo)準(zhǔn)輸入輸出設(shè)備。71“流”在文件上的應(yīng)用“文件”是存放在外存上的數(shù)據(jù)集合。最早的“文件”完全按照“流”的方式設(shè)計(jì):(1)創(chuàng)建文件/打開文件。建立內(nèi)存與文件的連接,并且要規(guī)定數(shù)據(jù)傳輸方向,因此有“為讀打開”、“為寫打開”等等。(2)讀/寫文件。在最早的文件系統(tǒng)中,讀和寫是分離的,“為讀打開”的文件就只能讀,“為寫打開”的文件就只能寫。以寫為例,先在內(nèi)存中把數(shù)據(jù)準(zhǔn)備好,即內(nèi)存緩沖區(qū),然后把這些數(shù)據(jù)一字節(jié)一字節(jié)地送到文件中存放。(3)關(guān)閉文件。撤除第(1)步建立的連接?,F(xiàn)在的文件系統(tǒng)除了允許同時(shí)為“讀”和“寫”建立一個(gè)連接之外,其它方面沒有改變。72cin與cout

cin是標(biāo)準(zhǔn)輸入設(shè)備流,一般直接對(duì)應(yīng)鍵盤,流的方向是由鍵盤向內(nèi)存;cout是標(biāo)準(zhǔn)輸出設(shè)備流,一般直接對(duì)應(yīng)顯示器,流的方向是由內(nèi)存向顯示器。計(jì)算機(jī)開機(jī)后,由系統(tǒng)建立cin、cout和內(nèi)存的連接,并且始終處于連接狀態(tài),使用完畢后不需要也不能關(guān)閉。73cin、cout與類型轉(zhuǎn)換

cin和cout都按“文本形式”工作,并帶有數(shù)據(jù)類型轉(zhuǎn)換功能。以cout為例,cout<<x,不論變量x是int、char、double等哪一種類型,cout都能夠把數(shù)據(jù)的內(nèi)存形式轉(zhuǎn)換成文本的ASCII形式,再逐個(gè)符號(hào)地傳送到顯示器上。

cin和cout具有可擴(kuò)展性、對(duì)于類、結(jié)構(gòu)體等不是基本數(shù)據(jù)類型的情況,可以通過(guò)對(duì)“<<”和“>>”進(jìn)行運(yùn)算符重載,使得cin、cout支持自定義類型。當(dāng)然,類通常會(huì)設(shè)計(jì)輸入、輸出對(duì)應(yīng)的方法成員完成相應(yīng)的工作。74“在一批數(shù)據(jù)中找一個(gè)滿足的”,這是非常常用的操作,可以設(shè)計(jì)出針對(duì)各種類型的數(shù)組進(jìn)行查找的函數(shù)模板:

template<typenameT>

int

Find(Tx[],intn,Tkey) { inti;

for(

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(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ì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論