版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(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)類(lèi)似于原運(yùn)算符的功能繼承與組合——如何利用已有的類(lèi)建立更復(fù)雜的對(duì)象虛函數(shù)——指針指向類(lèi)族中的哪個(gè)對(duì)象,就調(diào)用該對(duì)象相應(yīng)的方法成員抽象類(lèi)——類(lèi)中只規(guī)定有哪些行為,但并不具體實(shí)現(xiàn)多態(tài)——讓同一種行為應(yīng)用于各種對(duì)象、各種情況模板——提高編碼的效率異常處理——設(shè)置錯(cuò)誤處理代碼,應(yīng)對(duì)可能出現(xiàn)的錯(cuò)誤const——保護(hù)數(shù)據(jù),防止被意外破壞流——把不同類(lèi)型的信息視為一個(gè)數(shù)據(jù)序列泛型——忽略數(shù)據(jù)元素在存儲(chǔ)上的差異,強(qiáng)調(diào)行為上的共性,強(qiáng)化代碼的通用性2類(lèi)是規(guī)定行為的集合 基本類(lèi)型 自定義類(lèi)集合示例 int
CMyEmployee元素示例 15 2010053134,張三,男,1982.3.5.
運(yùn)算 算術(shù)運(yùn)算 規(guī)定的行為(方法)
類(lèi)是基本數(shù)據(jù)類(lèi)型的擴(kuò)展,兩者的核心都是集合及集合上的運(yùn)算,基本類(lèi)型的運(yùn)算表現(xiàn)為“+”、“-”、“*”、“/”等算術(shù)運(yùn)算,是固有運(yùn)算,可直接使用。定義類(lèi)中包含哪些數(shù)據(jù)元素相對(duì)簡(jiǎn)單。類(lèi)的核心問(wèn)題是定義類(lèi)的方法成員,通過(guò)方法成員表現(xiàn)出類(lèi)的元素(對(duì)象)具有哪些行為。3對(duì)象的屬性與操作對(duì)象的行為通常可以分為計(jì)算類(lèi)和非計(jì)算類(lèi)。非計(jì)算類(lèi)包括顯示、存儲(chǔ)、傳輸?shù)刃袨?,比如關(guān)于圖形處理建立的區(qū)域類(lèi)族大體上會(huì)有三角形、方形、多邊形等自定義類(lèi),各個(gè)對(duì)象都有在屏幕上畫(huà)出該形狀這一行為,而且通常都用同一個(gè)成員名來(lái)描述這個(gè)行為,如“對(duì)象.Draw()”。這一現(xiàn)象將在下一節(jié)“抽象類(lèi)”當(dāng)中討論。
計(jì)算類(lèi)行為是指獲取對(duì)象的相關(guān)信息,或者通過(guò)對(duì)象及其它數(shù)據(jù)計(jì)算得到一些信息。比如上述關(guān)于區(qū)域的類(lèi)族,各個(gè)對(duì)象通常都需要對(duì)外公布(允許外部訪問(wèn),public)寬度和高度兩個(gè)數(shù)據(jù),這樣的信息稱(chēng)為“對(duì)象的屬性”,通常也有相對(duì)固定的成員名,例如取對(duì)象的寬度通常寫(xiě)作“對(duì)象.GetWidth()”。這一類(lèi)行為當(dāng)中包含運(yùn)算符重載。4為什么要有運(yùn)算符重載?起因(在上一單元已述,重現(xiàn)):
(1)常規(guī)的運(yùn)算符只運(yùn)用于基本數(shù)據(jù)類(lèi)型,并且有固定的用法,基本上與數(shù)學(xué)上的用法一致?!糜?/p>
(2)類(lèi)是數(shù)據(jù)與處理(稱(chēng)為“方法”)的結(jié)合體,有很多處理與常規(guī)的運(yùn)算有直接聯(lián)系,或者是常規(guī)運(yùn)算在意思上的延伸,比如CString類(lèi)的加法延伸為拼接。
——好理解
(3)設(shè)計(jì)一個(gè)用于實(shí)現(xiàn)加法的函數(shù)Add,帶有兩個(gè)入口參數(shù)分別記作a和b,則調(diào)用該函數(shù)寫(xiě)作“Add(a,b)”,這一寫(xiě)法當(dāng)然不如“a+b”更簡(jiǎn)潔易懂。——好寫(xiě)目標(biāo):
希望為類(lèi)設(shè)計(jì)一個(gè)與常規(guī)運(yùn)算符在意義上接近的處理或者計(jì)算,并且沿用常規(guī)運(yùn)算符原有的寫(xiě)法5運(yùn)算符重載方式重載方式用成員函數(shù)重載用友元函數(shù)重載 特 點(diǎn)“=”等少量的幾個(gè)運(yùn)算符必須用成員函數(shù)的方式重載重載二元運(yùn)算符時(shí),右側(cè)的操作數(shù)可以是各種類(lèi)型,但左側(cè)的操作數(shù)必須是類(lèi)的對(duì)象成員函數(shù)的形參數(shù)目等于運(yùn)算符操作數(shù)的數(shù)量減1(1)通常用全局函數(shù)實(shí)現(xiàn)(2)需要訪問(wèn)類(lèi)的私有成員時(shí)才需要定義成友元函數(shù)6不能重載的運(yùn)算符 以下運(yùn)算符不能被重載:
成員訪問(wèn)
.
域限制符 ::
條件運(yùn)算 ?: 取字節(jié)數(shù) sizeof7經(jīng)常被重載的運(yùn)算符運(yùn)算符 分類(lèi) 重載方式+,-,*,/,% 算術(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類(lèi)定義前置“++”前述CClock類(lèi)的聲明如下: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類(lèi)的對(duì)象是時(shí)鐘,“++”的功能顯而易見(jiàn)。用成員函數(shù)為CClock類(lèi)定義前置“++”,首先需要在類(lèi)中添加相應(yīng)的函數(shù)聲明。注意,類(lèi)中已有Stepup函數(shù)可以利用9編寫(xiě)“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ù)值,甚至可以沒(méi)有形參的名字;(2)不要忘記在類(lèi)中添加相應(yīng)的函數(shù)聲明10友元函數(shù)定義前置“++”CClock類(lèi)的聲明如下: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;}最初編寫(xiě)代碼的時(shí)候忘記了引用,沒(méi)有引用是不行的12為CClock定義下標(biāo)[]設(shè)x是CClock類(lèi)的對(duì)象,即一個(gè)時(shí)鐘,原本x[?]是沒(méi)有意義的,但不妨人為地做如下定義:
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),則在寫(xiě)法上“x[i]”是函數(shù)調(diào)用“x.operator[](i)”的變形,“k=x[i]”也可以寫(xiě)成:
k=x.operator[](i)13為CClock類(lèi)定義“[]”在CClock類(lèi)中添加關(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類(lèi)的“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)算符重載,可以把原本沒(méi)有意義的寫(xiě)法“x[?]”賦予確定的含義,這與前述的運(yùn)算符重載有著重大差異。
既然如此,對(duì)于任意一個(gè)允許重載的運(yùn)算符,也可以賦予它與原運(yùn)算符完全沒(méi)有關(guān)聯(lián)的功能。但是極少有人這樣用,因?yàn)檫\(yùn)算符重載的目的在于借用運(yùn)算符原有的含義、用原有的寫(xiě)法實(shí)現(xiàn)對(duì)象的某些處理功能,如果這些功能與被重載的運(yùn)算符相去甚遠(yuǎn),則重載的效果只會(huì)讓人造成概念上的混亂,不利于軟件開(kāi)發(fā)。正如在定義一個(gè)函數(shù)時(shí),通常都以與函數(shù)功能相關(guān)的英文單詞或者編寫(xiě)作為函數(shù)名。16CClock類(lèi)的“operator()”對(duì)于對(duì)象x,運(yùn)算符重賦予了“x[?]”一定的意義,對(duì)于同樣原本沒(méi)有意義的“x(?)”也可以依照此例處理。實(shí)際上,把對(duì)“[]”重載時(shí)所有的“[”換成“(”、所有的“]”換成“)”,前述代碼同樣可以編譯通過(guò)。很多資料上把“operator()”稱(chēng)為函數(shù)調(diào)用運(yùn)算符,這容易在概念上造成混亂。建議:不用管它叫什么名字,因?yàn)閷?duì)于對(duì)象x而言,“x(?)”原本沒(méi)有意義,現(xiàn)在通過(guò)運(yùn)算符重載規(guī)定了該寫(xiě)法的含義。17繼承還是組合面向?qū)ο蟪绦蛟O(shè)計(jì)的基本設(shè)計(jì)單位是“類(lèi)”,類(lèi)的本質(zhì)是規(guī)定了對(duì)象的數(shù)據(jù)信息和行為。設(shè)計(jì)更復(fù)雜的程序時(shí),可以利用已有的類(lèi),在利用方法上就有了本頁(yè)的標(biāo)題:繼承還是組合?——本節(jié)只考慮public繼承設(shè)X和Y是兩個(gè)類(lèi),x是X的對(duì)象,y是Y的對(duì)象繼承(“isa”關(guān)系)——如果X是Y的派生類(lèi),則:
xisay. (見(jiàn)下頁(yè)圖元類(lèi)族示例)組合(“hasa”關(guān)系)——如果y是x的一個(gè)子對(duì)象,則:
xhasay.例如:CMyEmployee類(lèi)中包含兩個(gè)CString子對(duì)象,
Theemployeehasanumber. Theemployeehasaname.18繼承描述“isa”關(guān)系Point(點(diǎn))isaelement(圖元)Rigion(區(qū)域)isaelement(圖元)Circle(方形)isaRigion(區(qū)域)...... 圖元顏色,尺寸,邊界畫(huà)圖,擦除,取邊界點(diǎn)線起點(diǎn),終點(diǎn),線型區(qū)域填充模式,透明度直線弧線......曲線......方形......圓形......多邊形......注意,不論是繼承還是組合,在x中都包含一個(gè)y的對(duì)象作為x的一部分!繼承與組合到底有什么差別?19繼承與組合的差異xisay(繼承)(1)編寫(xiě)X類(lèi)的成員函數(shù)代碼時(shí),可以訪問(wèn)y的public成員和protected成員,包括方法成員也包括數(shù)據(jù)成員(2)在類(lèi)的外部編寫(xiě)代碼時(shí),可以訪問(wèn)x的public成員,也能訪問(wèn)y的public成員(3)CX的構(gòu)造函數(shù)以“:CY(...)”指明如何調(diào)用基類(lèi)的構(gòu)造函數(shù)xhasay(組合)(1)編寫(xiě)X類(lèi)的成員函數(shù)代碼時(shí),只能訪問(wèn)y的public成員,包括方法成員和數(shù)據(jù)成員(2)在類(lèi)的外部編寫(xiě)代碼時(shí),只能訪問(wèn)x的public成員(3)CX的構(gòu)造函數(shù)以“:子對(duì)象名(...)”指明如何調(diào)用子對(duì)象的構(gòu)造函數(shù)20測(cè)試1,派生類(lèi)內(nèi)部CY類(lèi)的聲明:classCY{public:f1();
intd1;protected:f2();
intd2;private:f3();
intd3;}CX類(lèi)的聲明:classCX:publicCY//繼承{public:f_x1();
intd_x1;protected:f_x2();
intd_x2;private:f_x3();
intd_x3;}編寫(xiě)CX的函數(shù)代碼時(shí),允許訪問(wèn)CX和CY的哪些成員?21測(cè)試2,派生類(lèi)外部CY類(lèi)的聲明:classCY{public:f1();
intd1;protected:f2();
intd2;private:f3();
intd3;}CX類(lèi)的聲明:classCX:publicCY//繼承{public:f_x1();
intd_x1;protected:f_x2();
intd_x2;private:f_x3();
intd_x3;}x是CX的對(duì)象,“x.?”是合法的訪問(wèn)?22測(cè)試3,組合類(lèi)內(nèi)部CY類(lèi)的聲明:classCY{public:f1();
intd1;protected:f2();
intd2;private:f3();
intd3;}編寫(xiě)CX的函數(shù)代碼時(shí),允許訪問(wèn)CX和CY的哪些成員?CX類(lèi)的聲明:classCX //組合{public:f_x1();CYy1;protected:f_x2();CYy2;private:f_x3();CYy3;}訪問(wèn)CY的成員時(shí),必須指明訪問(wèn)哪一個(gè)子對(duì)象的成員,比如“y1.f1()”、“y2.f1()”、“y3.d1=5”23測(cè)試4,組合類(lèi)外部CY類(lèi)的聲明:classCY{public:f1();
intd1;protected:f2();
intd2;private:f3();
intd3;}CX類(lèi)的聲明:classCX //組合{public:f_x1();CYy1;protected:f_x2();CYy2;private:f_x3();CYy3;}x是CX的對(duì)象,“x.?”是合法的訪問(wèn)?x.f_x1() x.y1.f1() x.y1.d1=5;24多用組合少用繼承如本頁(yè)標(biāo)題所示,在建立新的類(lèi)時(shí),多用組合少用繼承。并且把子對(duì)象置于private保護(hù)之下。原因:面向?qū)ο蟮暮诵乃枷胫皇欠庋b,即允許外部訪問(wèn)對(duì)象的哪些成員。以繼承的方式建立新的類(lèi),編寫(xiě)代碼的人往往容易忽略可以從外部訪問(wèn)基類(lèi)的public成員,從而導(dǎo)致一些預(yù)料之外的信息暴露。當(dāng)然,最根本的還是根據(jù)“isa”還是“hasa”關(guān)系來(lái)選用繼承和組合。25繼承導(dǎo)致類(lèi)族轉(zhuǎn)換話題:面向?qū)ο蟮某绦蛟O(shè)計(jì)模式中經(jīng)常會(huì)設(shè)計(jì)一系列有繼承與派生關(guān)系的類(lèi),從一個(gè)基類(lèi)開(kāi)始往下派生出的所有的類(lèi)形成一個(gè)“類(lèi)族”。類(lèi)族的設(shè)計(jì)思想顯然是為了代碼重用。在一個(gè)類(lèi)族中,對(duì)象盡管屬于不同的類(lèi),但通常都有一些相同的特征或者行為。即:類(lèi)族中任意一個(gè)類(lèi)的對(duì)象都擁有基類(lèi)的數(shù)據(jù)成員(雖然有可能因?yàn)槔^承方式而不能訪問(wèn)),視作具有相同的特征信息;類(lèi)族中的對(duì)象通常也具有一些同名的函數(shù)成員,視作具有相同的行為,這些函數(shù)的功能相同或相似,但實(shí)現(xiàn)的具體代碼可以不同。26類(lèi)族對(duì)象的共性例如,以“圖元”為基類(lèi)的類(lèi)族具有顏色、尺寸等共同的數(shù)據(jù)成員,以及畫(huà)、擦等同名的方法成員;除此之外,以“區(qū)域”為基類(lèi)的類(lèi)族還具有填充模式、透明度這兩個(gè)共同的數(shù)據(jù)成員。圖元顏色,尺寸,邊界畫(huà)圖,擦除,取邊界點(diǎn)線起點(diǎn),終點(diǎn),線型區(qū)域填充模式,透明度直線弧線......曲線......方形......圓形......多邊形......27對(duì)圖元類(lèi)族確定名稱(chēng)為了后續(xù)敘述的方便,為各個(gè)類(lèi)及各個(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();原本沒(méi)有疑問(wèn)的用法會(huì)因?yàn)橹羔樁a(chǎn)生歧義,見(jiàn)下頁(yè)。29重要規(guī)則C++規(guī)定:
派生類(lèi)的地址可以賦值給指向基類(lèi)的指針變量你如何理解這個(gè)規(guī)則?請(qǐng)先看下面的例子為了說(shuō)明問(wèn)題的簡(jiǎn)便,改用下面的最簡(jiǎn)單的類(lèi)聲明:classCA{public: voidfun() {cout<<"FunofCA\n";};};classCB:publicCA{public: voidfun() {cout<<"FunofCB\n";}; voidfb(){cout<<"Thisisfb\n";};};記住各函數(shù)的顯示效果!30類(lèi)族中的指針指向指出下面代碼中的錯(cuò)誤:main(){ CAx,*p; CBy,*q; p=&y; q=&x; p->fun(); p->fb(); q->fun();}派生類(lèi)地址可以賦值給指向基類(lèi)的指針變量,反之不行這一行是對(duì)的,不用寫(xiě)“p=(CA*)&y;”p的類(lèi)型決定了通過(guò)p只能訪問(wèn)CA的成員,fb是CB的成員但不是CA的成員31指針指向類(lèi)族中的對(duì)象指出下面代碼中的運(yùn)行結(jié)果:main(){ CAx,*q; CBy;
x.fun(); q=&x; q->fun();
y.fun(); q=&y; q->fun();}最后一行顯示值得探討:q是指向基類(lèi)CA的指針變量,但此時(shí)指向派生類(lèi)對(duì)象y,“q->fun()”到底調(diào)用哪個(gè)函數(shù)?另外,編程者希望它調(diào)用哪個(gè)函數(shù)?32再談規(guī)則上述規(guī)則的意義:(1)因?yàn)榇a重用而產(chǎn)生了類(lèi)族,類(lèi)族中的對(duì)象都有相同或者相似的行為。在編程者看來(lái),類(lèi)族中的對(duì)象都是“差不多”的。(2)編程者希望借用一個(gè)指針變量,不論該指針指向類(lèi)族中的哪一個(gè)對(duì)象,都能正確地訪問(wèn)相應(yīng)的成員。如果派生類(lèi)對(duì)基類(lèi)的某個(gè)方法成員編寫(xiě)了新代碼(覆蓋),則希望指針指向派生類(lèi)對(duì)象時(shí),能夠訪問(wèn)新代碼。(3)以“基類(lèi)*q”定義指針變量,則通過(guò)q只能訪問(wèn)基類(lèi)的成員,而不能訪問(wèn)派生類(lèi)新增的成員,從而保證不會(huì)出現(xiàn)訪問(wèn)一個(gè)不存在的成員的現(xiàn)象。派生類(lèi)地址可以賦值給指向基類(lèi)的指針變量,反之不行前述示例說(shuō)明沒(méi)能做到這一點(diǎn)33虛函數(shù)虛函數(shù)專(zhuān)門(mén)用于解決上述問(wèn)題:如前例,基類(lèi)中定義了方法成員fun,派生類(lèi)更新了該方法。以“CA*q;”定義指針變量,希望當(dāng)q指向基類(lèi)CA的對(duì)象時(shí),“q->fun()”訪問(wèn)基類(lèi)CA的成員函數(shù)fun;當(dāng)q指向派生類(lèi)CB的對(duì)象時(shí),“q->fun()”訪問(wèn)派生類(lèi)CB更新之后的成員函數(shù)fun。簡(jiǎn)言之:希望q指向誰(shuí)就調(diào)用誰(shuí)的成員函數(shù)對(duì)于上述需求,需要在基類(lèi)中把該方法成員定義成“虛函數(shù)”。聲明虛函數(shù)的格式如下:
virtual
返回值類(lèi)型函數(shù)名(形參表);34聲明虛函數(shù)下面是定義CA和CB兩個(gè)類(lèi),在適當(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ō)明類(lèi)的靜態(tài)成員函數(shù)和內(nèi)聯(lián)函數(shù)不能聲明為虛函數(shù)定義成員函數(shù)為虛函數(shù),并不代表該函數(shù)是“虛”的,而是為了通過(guò)指針變量能夠訪問(wèn)正確的方法成員,通過(guò)對(duì)象名訪問(wèn)成員與虛函數(shù)無(wú)關(guān)一旦在一個(gè)類(lèi)中定義了虛函數(shù),則以該類(lèi)為起點(diǎn)的類(lèi)族中該函數(shù)都是虛函數(shù),派生類(lèi)中的相應(yīng)函數(shù)不再需要用virtual說(shuō)明構(gòu)造函數(shù)不能聲明為虛函數(shù),析構(gòu)函數(shù)往往聲明為虛函數(shù)基類(lèi)中聲明虛函數(shù)時(shí)必須明確形參,派生類(lèi)中相應(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è)類(lèi)的對(duì)象能訪問(wèn)哪些函數(shù)成員?哪些類(lèi)的哪些函數(shù)構(gòu)成一組虛函數(shù)畫(huà)出層次結(jié)構(gòu)圖37虛函數(shù)的實(shí)現(xiàn)原理面向?qū)ο蟪绦蛟O(shè)計(jì)允許函數(shù)重載(overload)與函數(shù)覆蓋(override),前者導(dǎo)致函數(shù)同名但形參不同,后者則是同名同形參。前面已有若干示例說(shuō)明后者的有關(guān)規(guī)則,核心問(wèn)題是當(dāng)代碼中出現(xiàn)一個(gè)函數(shù)調(diào)用時(shí),究竟是調(diào)用哪一段具體的函數(shù)代碼。解決問(wèn)題的方法是對(duì)虛函數(shù)采用動(dòng)態(tài)聯(lián)編方式。動(dòng)態(tài)聯(lián)編——也稱(chēng)動(dòng)態(tài)綁定,是與靜態(tài)聯(lián)編相對(duì)而言的。當(dāng)類(lèi)族中含有虛函數(shù)時(shí),為類(lèi)族的每個(gè)對(duì)象安排虛函數(shù)表(是各個(gè)虛函數(shù)入口地址的列表,與數(shù)據(jù)成員安排在一起)。對(duì)于通過(guò)指向基類(lèi)的指針訪問(wèn)函數(shù)成員的情況,編譯時(shí)處理成“從虛函數(shù)表中找函數(shù)的入口地址”。38設(shè)計(jì)圖元類(lèi)族的方法成員Q:請(qǐng)?jiān)O(shè)計(jì)CElement類(lèi)的Draw方法的功能及代碼CElementcolor,size,borderDraw,Erase,...CPointCSegmentstart,end,styleCAreapattern,transparencyCLineCArc......CCurve......CSquare......CCircle......CPolygon......Draw的功能好說(shuō),就是在指定位置畫(huà)出這個(gè)圖元。代碼沒(méi)法寫(xiě),因?yàn)樵贑Element類(lèi)中并不知道圖元的具體情況。如果真的要寫(xiě)代碼,只能是空代碼,什么也不做!39純虛函數(shù)與抽象類(lèi)采用繼承與派生的層次式設(shè)計(jì)構(gòu)建一個(gè)類(lèi)族時(shí),越上層的類(lèi)就越抽象,越下層的類(lèi)就越具體。有時(shí)上層的方法根本無(wú)法明確行為,比如“圖元”的Draw
在C++中,允許一個(gè)類(lèi)只規(guī)定方法成員的首部而不編寫(xiě)函數(shù)體,這樣的方法稱(chēng)為“純虛函數(shù)”,含有純虛函數(shù)的類(lèi)稱(chēng)為“抽象類(lèi)”。純虛函數(shù)是在類(lèi)聲明中用如下形式定義函數(shù)成員:
virtual函數(shù)值類(lèi)型函數(shù)名(形參表)=0;注意,上述格式中的“=0”表示該函數(shù)是純虛函數(shù)。雖然在語(yǔ)法上virtual不是必須的,但一般只有類(lèi)族中基類(lèi)的虛函數(shù)才設(shè)計(jì)成不編寫(xiě)函數(shù)體。40抽象類(lèi)的作用抽象類(lèi)中至少含有一個(gè)純虛函數(shù),試圖調(diào)用純虛函數(shù)將導(dǎo)致沒(méi)有相應(yīng)的代碼可以執(zhí)行,所以,不允許創(chuàng)建抽象類(lèi)的對(duì)象!抽象類(lèi)的作用表現(xiàn)在規(guī)定由此向下的一個(gè)類(lèi)族(或者類(lèi)族分支)中有哪些共同的方法成員,并統(tǒng)一這些方法成員的函數(shù)名稱(chēng)及參數(shù)形式。比如,關(guān)于“圖元”的類(lèi)族中,“圖元”定義方法成員“Draw”,“線”定義方法成員“GetLength”,區(qū)域定義方法成員“GetArea”,這些方法都無(wú)法編寫(xiě)代碼,但在相應(yīng)的類(lèi)族中有相同的名稱(chē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ù)類(lèi)而言,外界不能直接訪問(wèn)對(duì)象的數(shù)據(jù)成員,只能通過(guò)類(lèi)所提供的方法成員獲取信息,或者令對(duì)象產(chǎn)生相應(yīng)的行為。所以,面向?qū)ο笾械摹敖涌凇蓖ǔV赋蓡T函數(shù)。42多態(tài)的種類(lèi)有資料把多態(tài)劃分為通用多態(tài)和特定多態(tài),前者包括參數(shù)多態(tài)和包含多態(tài),后者包括重載多態(tài)和強(qiáng)制多態(tài),但這樣的劃分值得商榷,原因見(jiàn)下頁(yè)1.參數(shù)多態(tài)——由函數(shù)模板產(chǎn)生的模板函數(shù)(同名函數(shù)處理不同類(lèi)型的數(shù)據(jù)),由類(lèi)模板產(chǎn)生的模板類(lèi),除了數(shù)據(jù)類(lèi)型不同,其它部分相同2.包含多態(tài)——類(lèi)族中同名成員函數(shù),在指針指向某對(duì)象時(shí),動(dòng)態(tài)綁定相應(yīng)的函數(shù)成員3.重載多態(tài)——函數(shù)重載、運(yùn)算符重載,以同名函數(shù)處理不同數(shù)量、不同類(lèi)型的數(shù)據(jù)4.強(qiáng)制多態(tài)——某些運(yùn)算符具有自動(dòng)數(shù)據(jù)類(lèi)型轉(zhuǎn)換功能,如“int+double”時(shí),先把int轉(zhuǎn)換成double,再進(jìn)行加法運(yùn)算多態(tài)的四種形式43歸并一下多態(tài)的種類(lèi)多態(tài)的作用在于以相同或者相似的形式處理不同類(lèi)型、不同數(shù)量的數(shù)據(jù),或者處理不同類(lèi)的對(duì)象。分析前述劃分,可以再歸并一下,得到三個(gè)種類(lèi):1.函數(shù)重載(overload),以同一范圍內(nèi)的一組同名函數(shù)應(yīng)對(duì)不同數(shù)量、類(lèi)型的數(shù)據(jù)2.函數(shù)覆蓋(override),以類(lèi)族中的同名函數(shù)應(yīng)對(duì)類(lèi)族中的各個(gè)對(duì)象3.自動(dòng)轉(zhuǎn)換(含運(yùn)算符重載),基本運(yùn)算符應(yīng)對(duì)不同類(lèi)型的數(shù)據(jù)/對(duì)象只有類(lèi)模板不在此列。先看看什么是類(lèi)模板,什么是模板類(lèi),似曾相識(shí)的概念。44函數(shù)模板:由template開(kāi)始編寫(xiě)的一段函數(shù)定義,表示一組函數(shù),除了類(lèi)型標(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í)其中未定的類(lèi)型怎么處理? 根據(jù)調(diào)用時(shí)參數(shù)的類(lèi)型將相應(yīng)的類(lèi)型標(biāo)識(shí)符代替模板中的類(lèi)型標(biāo)記復(fù)習(xí):函數(shù)模板與模板函數(shù)函數(shù)模板:模板函數(shù):函數(shù)模板并不是函數(shù)定義,為什么可以直接調(diào)用?由誰(shuí)來(lái)生成函數(shù)定義代碼?在什么時(shí)候生成?生成函數(shù)代碼時(shí)其中未定的類(lèi)型怎么處理?45類(lèi)模板:由template開(kāi)始編寫(xiě)的一段類(lèi)聲明(含其中的成員函數(shù)代碼),其中除了含有特定的類(lèi)型標(biāo)記,表示一組類(lèi)聲明,除了類(lèi)型標(biāo)記不同、其它部分都相同模板類(lèi):由類(lèi)模板生成的類(lèi)類(lèi)模板并不是類(lèi),為什么可以直接定義它的對(duì)象? 因?yàn)橛深?lèi)模板可以生成相應(yīng)的類(lèi)定義,即類(lèi)聲明由誰(shuí)來(lái)生成類(lèi)聲明的代碼?在什么時(shí)候生成? 編譯器在首次遇到使用模板類(lèi)的時(shí)候生成生成類(lèi)聲明的代碼時(shí)其中未定的類(lèi)型怎么處理? 使用模板類(lèi)時(shí)需要指明類(lèi)模板中的類(lèi)型標(biāo)記用什么具體的類(lèi)型標(biāo)識(shí)符代替類(lèi)模板與模板類(lèi)46一個(gè)簡(jiǎn)單的類(lèi)模板先來(lái)個(gè)最簡(jiǎn)單的。如果想根據(jù)下面的類(lèi)來(lái)定義一個(gè)類(lèi)模板,讓其中的int可以是各種數(shù)據(jù)類(lèi)型:
classCA { public: CA(int
n){mm=n;}; voidf(){cout<<mm<<endl;};
intmm; };template<typename
T>TTCA<T>如果想在類(lèi)聲明之后再寫(xiě)函數(shù)體,怎么辦?47template<typenameT>classCA{public: CA<T>(Tn){mm=n;}; voidf(){cout<<mm<<endl;}; Tmm;};類(lèi)模板后面寫(xiě)成員函數(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ù)的類(lèi)模板如果類(lèi)模板中需要兩個(gè)不同類(lèi)型的參數(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類(lèi)模板只聲明了生成若干個(gè)類(lèi)的可能性,只有在編譯器遇到對(duì)類(lèi)的實(shí)際使用時(shí)(比如定義類(lèi)的對(duì)象),才會(huì)生成相應(yīng)的類(lèi)——稱(chēng)為類(lèi)模板的實(shí)例化類(lèi)模板實(shí)例化時(shí)必須顯式指明模板所含參數(shù)的類(lèi)型類(lèi)模板中除了在class后面首次出現(xiàn)的類(lèi)名之外,其它用到類(lèi)名的時(shí)候都要寫(xiě)“類(lèi)名<參數(shù)表>”的完整寫(xiě)法,但構(gòu)造函數(shù)、析構(gòu)函數(shù)則可以省略為只用“類(lèi)名”在類(lèi)聲明之后編寫(xiě)成員函數(shù)代碼時(shí),需要重新寫(xiě)template及參數(shù),參數(shù)的數(shù)量必須相同,參數(shù)名稱(chēng)可變,而且類(lèi)限制符“::”前面的類(lèi)名必須用完整寫(xiě)法類(lèi)模板規(guī)則要點(diǎn)52針對(duì)下面的要求設(shè)計(jì)類(lèi)模板CArray:能夠存放一批數(shù)據(jù)成員函數(shù)GetData能夠根據(jù)輸入情況確定存放多少個(gè)數(shù)據(jù),并從鍵盤(pán)上讀取這一批數(shù)據(jù)成員函數(shù)Display能夠顯示當(dāng)前存放的數(shù)據(jù)成員函數(shù)Sort能夠?qū)Ξ?dāng)前存放的數(shù)據(jù)排序(升序)為了測(cè)試,安排主函數(shù)如下,并要求替換其中的double為int、float、char等常用類(lèi)型多次測(cè)試
voidmain() {CArray<double>x;
x.GetData();
x.Display();
x.Sort();
x.Display(); }復(fù)雜一點(diǎn)的類(lèi)模板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;};定義類(lèi)模板54template<typenameT>int
CArray<T>::GetData(){ int
i,n;
cout<<"Howmanynumbers:";
cin>>n;
if(n<=0) return0;//沒(méi)有數(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;}編寫(xiě)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"; }}編寫(xiě)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; }}//終于編寫(xiě)完了,測(cè)試一下吧編寫(xiě)Sort57高手編的軟件不會(huì)死下面是一個(gè)常見(jiàn)現(xiàn)象:通常,要么等待數(shù)秒之后軟件被關(guān)閉,要么就這么一直等下去。如何看待這一現(xiàn)象?58軟件中的BUG什么原因造成了軟件崩潰?
(1)非法命令 (2)錯(cuò)誤的語(yǔ)序例,指出以下代碼中存在的問(wèn)題或者錯(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è)可能的問(wèn)題:輸入到n的值不合適,比如負(fù)數(shù);用new申請(qǐng)內(nèi)存空間可能失敗59錯(cuò)誤種類(lèi)這里的“非法命令”不是指語(yǔ)法錯(cuò)誤(語(yǔ)法錯(cuò)誤由編譯器處理),而是指命令計(jì)算機(jī)執(zhí)行一個(gè)不正確的操作,包括以下幾種情況:非法訪問(wèn)內(nèi)存。比如前例中對(duì)x[n]賦值非法操作。比如前例中可能存在的除以0非法訪問(wèn)硬件。連接到計(jì)算機(jī)的各種設(shè)備各有各的使用特點(diǎn),有些只讀,有些只寫(xiě),有些要求先做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)問(wè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í)出了問(wèn)題,比如問(wèn)題在func_A中,通常需要以函數(shù)值的方式逐層“上報(bào)”,在某一層決定最終如何處理這個(gè)問(wèn)題62異常處理機(jī)制出現(xiàn)問(wèn)題逐級(jí)上報(bào)的處理方法代碼較大,異常處理機(jī)制是解決該問(wèn)題的另一種思路:不論哪一級(jí)出現(xiàn)問(wèn)題,只需要“報(bào)告一下”(不一定是對(duì)直接上級(jí)),稱(chēng)為“拋出異?!?。在某個(gè)函數(shù)中設(shè)置一段代碼來(lái)統(tǒng)一處理這些報(bào)告。統(tǒng)一處理異常由try和一組catch構(gòu)成,格式見(jiàn)下頁(yè);拋出異常則相對(duì)簡(jiǎn)單:
throw(參數(shù));其中,表示異常情況的參數(shù)可以是任何類(lèi)型的數(shù)據(jù),也可以是某個(gè)類(lèi)的對(duì)象,用途是向處理機(jī)制報(bào)告出現(xiàn)了什么樣的異常。63處理異常的編寫(xiě)格式處理異常的代碼部分由兩段構(gòu)成:try{可能拋出異常的代碼}catch(形參A){處理A}catch(形參B){處理B}catch(形參C){處理C}......這一段可能有問(wèn)題,沒(méi)關(guān)系,做就是了,有問(wèn)題就報(bào)告根據(jù)不同的錯(cuò)誤報(bào)告采取相應(yīng)的處理措施工作方式:在執(zhí)行try后面的代碼的過(guò)程中,只要有異常拋出,立即轉(zhuǎn)到catch部分,根據(jù)拋出的異常的類(lèi)型執(zhí)行對(duì)應(yīng)的處理代碼,如果沒(méi)有對(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ī)制僅僅是把編寫(xiě)代碼時(shí)在各個(gè)函數(shù)中對(duì)出現(xiàn)的問(wèn)題進(jìn)行處理改為在一個(gè)函數(shù)中統(tǒng)一處理,如果代碼中出現(xiàn)非法訪問(wèn)內(nèi)存、除以0等現(xiàn)象仍將導(dǎo)致軟件崩潰,另一種導(dǎo)致崩潰的原因是對(duì)拋出的異常沒(méi)有安排相應(yīng)的處理代碼。66防止意外修改數(shù)據(jù)被意外修改是另一個(gè)安全隱患。以編寫(xiě)函數(shù)為例,為了減少參數(shù)傳遞的開(kāi)銷(xiāo),有時(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;}沒(méi)有“&”是常規(guī)用法。如果用引用作為形參,在完成求值計(jì)算的同時(shí)會(huì)改變實(shí)際參數(shù)的值。這樣的修改往往并非有意為之,而是一種疏忽。67const有關(guān)規(guī)則A用const可以限制數(shù)據(jù)被修改,前述“常變量”是const的最初應(yīng)用。const的主要用法:(1)定義普通變量,限定不允許改變變量的值,即前述“常變量”:
const類(lèi)型變量名=初值;或者 類(lèi)型const變量名=初值;(2)定義普通對(duì)象,限定不允許訪問(wèn)對(duì)象的任何成員,不論是public、protected還是private:
const類(lèi)對(duì)象名(初值);或者 類(lèi)const對(duì)象名(初值);如此定義的對(duì)象又稱(chēng)“常對(duì)象”,用作初始化其它對(duì)象、給其它對(duì)象賦值等68const有關(guān)規(guī)則B(3)const用于定義指針變量時(shí)有所不同:① const類(lèi)型*變量名=初值;不允許改變指針?biāo)缸兞康闹担绻羔樦赶驅(qū)ο?,也不允許訪問(wèn)對(duì)象的任何成員,但可以令指針變量指向其它位置② 類(lèi)型*const變量名=初值;不允許改變指針變量所指位置,但可以改變指針?biāo)缸兞康闹?,如果指針指向?qū)ο螅试S訪問(wèn)對(duì)象的public成員③ const
類(lèi)型*const變量名=初值;兩者都不允許69const有關(guān)規(guī)則C(4)const用于定義引用:
const類(lèi)型&引用名=目標(biāo);不允許通過(guò)引用改變目標(biāo)的值,如果是對(duì)象的引用,也不允許通過(guò)引用訪問(wèn)對(duì)象的任何成員(5)const用于函數(shù)形參這種用法除了是在參數(shù)傳遞時(shí)確定初值之外,與前述相應(yīng)各種情況的規(guī)則對(duì)應(yīng)相同70什么是“流”這里所說(shuō)的“流”是以字節(jié)為單位進(jìn)行串行數(shù)據(jù)傳輸?shù)男问?。?jì)算機(jī)中還有一種是以“位”為單位的流,稱(chēng)“比特流”。對(duì)于一般的傳輸,總是需要有建立連接、傳輸、撤除連接三個(gè)步驟,這里的“流”加上一個(gè)特點(diǎn):?jiǎn)蜗?。?duì)于面向?qū)ο蟮木幊潭裕畛R?jiàn)的“流”是文件和標(biāo)準(zhǔn)輸入輸出設(shè)備。71“流”在文件上的應(yīng)用“文件”是存放在外存上的數(shù)據(jù)集合。最早的“文件”完全按照“流”的方式設(shè)計(jì):(1)創(chuàng)建文件/打開(kāi)文件。建立內(nèi)存與文件的連接,并且要規(guī)定數(shù)據(jù)傳輸方向,因此有“為讀打開(kāi)”、“為寫(xiě)打開(kāi)”等等。(2)讀/寫(xiě)文件。在最早的文件系統(tǒng)中,讀和寫(xiě)是分離的,“為讀打開(kāi)”的文件就只能讀,“為寫(xiě)打開(kāi)”的文件就只能寫(xiě)。以寫(xiě)為例,先在內(nèi)存中把數(shù)據(jù)準(zhǔn)備好,即內(nèi)存緩沖區(qū),然后把這些數(shù)據(jù)一字節(jié)一字節(jié)地送到文件中存放。(3)關(guān)閉文件。撤除第(1)步建立的連接?,F(xiàn)在的文件系統(tǒng)除了允許同時(shí)為“讀”和“寫(xiě)”建立一個(gè)連接之外,其它方面沒(méi)有改變。72cin與cout
cin是標(biāo)準(zhǔn)輸入設(shè)備流,一般直接對(duì)應(yīng)鍵盤(pán),流的方向是由鍵盤(pán)向內(nèi)存;cout是標(biāo)準(zhǔn)輸出設(shè)備流,一般直接對(duì)應(yīng)顯示器,流的方向是由內(nèi)存向顯示器。計(jì)算機(jī)開(kāi)機(jī)后,由系統(tǒng)建立cin、cout和內(nèi)存的連接,并且始終處于連接狀態(tài),使用完畢后不需要也不能關(guān)閉。73cin、cout與類(lèi)型轉(zhuǎn)換
cin和cout都按“文本形式”工作,并帶有數(shù)據(jù)類(lèi)型轉(zhuǎn)換功能。以cout為例,cout<<x,不論變量x是int、char、double等哪一種類(lèi)型,cout都能夠把數(shù)據(jù)的內(nèi)存形式轉(zhuǎn)換成文本的ASCII形式,再逐個(gè)符號(hào)地傳送到顯示器上。
cin和cout具有可擴(kuò)展性、對(duì)于類(lèi)、結(jié)構(gòu)體等不是基本數(shù)據(jù)類(lèi)型的情況,可以通過(guò)對(duì)“<<”和“>>”進(jìn)行運(yùn)算符重載,使得cin、cout支持自定義類(lèi)型。當(dāng)然,類(lèi)通常會(huì)設(shè)計(jì)輸入、輸出對(duì)應(yīng)的方法成員完成相應(yīng)的工作。74“在一批數(shù)據(jù)中找一個(gè)滿(mǎn)足的”,這是非常常用的操作,可以設(shè)計(jì)出針對(duì)各種類(lèi)型的數(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)益歸上傳用戶(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- YY/T 0581.2-2024輸液連接件第2部分:無(wú)針連接件
- 貴州大學(xué)《生物防治學(xué)》2023-2024學(xué)年第一學(xué)期期末試卷
- 2025年貴州省安全員《C證》考試題庫(kù)及答案
- 2025湖北建筑安全員《C證》考試題庫(kù)
- 2025山西建筑安全員《A證》考試題庫(kù)及答案
- 硅湖職業(yè)技術(shù)學(xué)院《唐詩(shī)宋詞賞析》2023-2024學(xué)年第一學(xué)期期末試卷
- 貴陽(yáng)學(xué)院《物流英語(yǔ)》2023-2024學(xué)年第一學(xué)期期末試卷
- 2025年河北建筑安全員C證(專(zhuān)職安全員)考試題庫(kù)
- 2025海南省安全員考試題庫(kù)及答案
- 2025年-黑龍江省安全員《A證》考試題庫(kù)及答案
- 駕駛員三年內(nèi)工作總結(jié)
- 廣東省深圳市羅湖區(qū)2023-2024學(xué)年二年級(jí)下學(xué)期期末考試數(shù)學(xué)試題
- 2023年第八屆“鵬程杯”六年級(jí)語(yǔ)文邀請(qǐng)賽試卷(初賽)
- 2023-2024學(xué)年成都市金牛區(qū)八年級(jí)上英語(yǔ)期末考試題(含答案)
- 更年期婦女健康管理專(zhuān)家共識(shí)1
- 青年你為什么要入團(tuán)-團(tuán)員教育主題班會(huì)-熱點(diǎn)主題班會(huì)課件
- MOOC 隧道工程-中南大學(xué) 中國(guó)大學(xué)慕課答案
- 司法鑒定工作應(yīng)急預(yù)案
- 《竹結(jié)構(gòu)建筑技術(shù)規(guī)程》
- 煤礦綜采工作面安全檢查
- 汽修廠消防培訓(xùn)課件
評(píng)論
0/150
提交評(píng)論