C++面向?qū)ο蟪绦蛟O(shè)計(jì)_第1頁
C++面向?qū)ο蟪绦蛟O(shè)計(jì)_第2頁
C++面向?qū)ο蟪绦蛟O(shè)計(jì)_第3頁
C++面向?qū)ο蟪绦蛟O(shè)計(jì)_第4頁
C++面向?qū)ο蟪绦蛟O(shè)計(jì)_第5頁
已閱讀5頁,還剩155頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

第2章C++面向?qū)ο蟪绦蛟O(shè)計(jì)

2.1類和對(duì)象2.2數(shù)據(jù)共享和成員特性2.3繼承和派生2.4多態(tài)和虛函數(shù)2.5運(yùn)算符重載2.6輸入/輸出流

第2章C++面向?qū)ο蟪绦蛟O(shè)計(jì)

2.1類和對(duì)象2.1類和對(duì)象2.1.1類的定義C++中定義類的一般格式如下:class<類名>{ private: [<私有型數(shù)據(jù)和函數(shù)>] public: [<公有型數(shù)據(jù)和函數(shù)>] protected: [<保護(hù)型數(shù)據(jù)和函數(shù)>]};<各個(gè)成員函數(shù)的實(shí)現(xiàn)>2.1類和對(duì)象2.1.1類的定義2.1.1類的定義當(dāng)類的成員函數(shù)的函數(shù)體在類的外部定義時(shí),必須由作用域運(yùn)算符“::”來通知編譯系統(tǒng)該函數(shù)所屬的類。例如:classCMeter{public: doublem_nPercent; //聲明一個(gè)公有數(shù)據(jù)成員 voidStepIt(); //聲明一個(gè)公有成員函數(shù) voidSetPos(intnPos); //聲明一個(gè)公有成員函數(shù) int GetPos() { returnm_nPos; } //聲明一個(gè)公有成員函數(shù)并定義private: intm_nPos; //聲明一個(gè)私有數(shù)據(jù)成員}; //注意分號(hào)不能省略voidCMeter::StepIt(){ m_nPos++;}voidCMeter::SetPos(intnPos){ m_nPos=nPos;}2.1.1類的定義當(dāng)類的成員函數(shù)的函數(shù)體在類的外部定義時(shí)2.1.2對(duì)象的定義與結(jié)構(gòu)類型一樣,它也有三種定義方式:聲明之后定義、聲明之時(shí)定義和一次性定義。但由于“類”比任何數(shù)據(jù)類型都要復(fù)雜得多,為了提高程序的可讀性,真正將“類”當(dāng)成一個(gè)密閉、“封裝”的盒子(接口),在程序中應(yīng)盡量在對(duì)象的聲明之后定義方式,并按下列格式進(jìn)行:<類名><對(duì)象名表>一個(gè)對(duì)象的成員就是該對(duì)象的類所定義的數(shù)據(jù)成員(成員變量)和成員函數(shù)。訪問對(duì)象的成員變量和成員函數(shù)和訪問變量和函數(shù)的方法是一樣的,只不過要在成員前面加上對(duì)象名和成員運(yùn)算符“.”,其表示方式如下:<對(duì)象名>.<成員變量><對(duì)象名>.<成員函數(shù)>(<參數(shù)表>)例如:myMeter.m_nPercent,myMeter.SetPos(2),Meters[0].StepIt();2.1.2對(duì)象的定義與結(jié)構(gòu)類型一樣,它也有三種定義方式:2.1.2對(duì)象的定義若對(duì)象是一個(gè)指針,則對(duì)象的成員訪問形式如下:<對(duì)象指針名>-><成員變量><對(duì)象指針名>-><成員函數(shù)>(<參數(shù)表>)“->”是一個(gè)表示成員的運(yùn)算符,它與“.”運(yùn)算符的區(qū)別是:“->”用來表示指向?qū)ο蟮闹羔樀某蓡T,而“.”用來表示一般對(duì)象的成員。2.1.2對(duì)象的定義若對(duì)象是一個(gè)指針,則對(duì)象的成員訪問形2.1.3類作用域和成員訪問權(quán)限1.類名的作用域如果在類聲明之前就需要使用該類名定義對(duì)象,則必須用下列格式在使用前進(jìn)行提前聲明(注意,類的這種形式的聲明可以在相同作用域中出現(xiàn)多次):class<類名>;例如:classCOne; //將類COne提前聲明classCOne; //可以聲明多次classCTwo{ //…private: COnea; //數(shù)據(jù)成員a是已定義的COne類對(duì)象};classCOne{ //…};2.1.3類作用域和成員訪問權(quán)限1.類名的作用域2.1.3類作用域和成員訪問權(quán)限2.類中成員的可見性(1)在類中使用成員時(shí),成員聲明的前后不會(huì)影響該成員在類中的使用,這是類作用域的特殊性。例如:classA{ voidf1() {

f2(); //調(diào)用類中的成員函數(shù)f2 cout<<a<<endl; //使用類中的成員變量a } voidf2(){} inta;};2.1.3類作用域和成員訪問權(quán)限2.類中成員的可見性2.1.3類作用域和成員訪問權(quán)限(2)由于類的成員函數(shù)可以在類體外定義,因而此時(shí)由“類名::”指定開始一直到函數(shù)體最后一個(gè)花括號(hào)為止的范圍也是該類作用域的范圍。例如:classA{ voidf1(); //…};voidA::f1(){ //…}則從A::開始一直到f1函數(shù)體最后一個(gè)花括號(hào)為止的范圍都是屬于類A的作用域。(3)在同一個(gè)類的作用域中,不管成員具有怎樣的訪問權(quán)限,都可在類作用域中使用,而在類作用域外卻不可使用。例如:classA{public: inta; //…};a=10; //錯(cuò)誤,不能在A作用域外直接使用類中的成員2.1.3類作用域和成員訪問權(quán)限(2)由于類的成員函數(shù)可2.1.3類作用域和成員訪問權(quán)限3.類外對(duì)象成員的可見性對(duì)于訪問權(quán)限public、private和protected來說,只有在子類中或用對(duì)象來訪問成員時(shí),它們才會(huì)起作用。在用類外對(duì)象來訪問成員時(shí),只能訪問public成員,而對(duì)private和protected均不能訪問。2.1.3類作用域和成員訪問權(quán)限3.類外對(duì)象成員的可見性2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)1.構(gòu)造函數(shù)C++規(guī)定,一個(gè)類的構(gòu)造函數(shù)必須與相應(yīng)的類同名,它可以帶參數(shù),也可以不帶參數(shù),與一般的成員函數(shù)定義相同,可以重載,也可以有默認(rèn)的形參值。例如:classCMeter{public: CMeter(intnPos) //帶參數(shù)的構(gòu)造函數(shù) { m_nPos=nPos; } //…}這樣若有:CMeteroMeter(10),oTick(20);2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)1.構(gòu)造函數(shù)2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)2.對(duì)構(gòu)造函數(shù)的幾點(diǎn)說明(1)構(gòu)造函數(shù)的約定使系統(tǒng)在生成類的對(duì)象時(shí)自動(dòng)調(diào)用。同時(shí),指定對(duì)象括號(hào)里的參數(shù)就是構(gòu)造函數(shù)的實(shí)參,例如,oMeter(10)就是oMeter.CMeter(10)。故當(dāng)構(gòu)造函數(shù)重載及設(shè)定構(gòu)造函數(shù)默認(rèn)形參值時(shí),要避免出現(xiàn)二義。CPerson(char*str,floath=170,floatw=130) //A{ strcpy(name,str); height=h; weight=w;}CPerson(char*str) //B{ strcpy(name,str);}2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)2.對(duì)構(gòu)造函數(shù)的幾點(diǎn)說明2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)(2)定義的構(gòu)造函數(shù)不能指定其返回值的類型,也不能指定為void類型。事實(shí)上,由于構(gòu)造函數(shù)主要用于對(duì)象數(shù)據(jù)成員的初始化,因而無須返回函數(shù)值,也就無須有返回類型。(3)若要用類定義對(duì)象,則構(gòu)造函數(shù)必須是公有型成員函數(shù),否則類無法實(shí)例化(即無法定義對(duì)象)。若類僅用于派生其他類,則構(gòu)造函數(shù)可定義為保護(hù)型成員函數(shù)。2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)(2)定義的構(gòu)造函數(shù)不能指定2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)3.默認(rèn)構(gòu)造函數(shù)實(shí)際上,在類定義時(shí),如果沒有定義任何構(gòu)造函數(shù),則編譯自動(dòng)為類隱式生成一個(gè)不帶任何參數(shù)的默認(rèn)構(gòu)造函數(shù),由于函數(shù)體是空塊,因此默認(rèn)構(gòu)造函數(shù)不進(jìn)行任何操作,僅僅為了滿足對(duì)象創(chuàng)建時(shí)的語法需要。其形式如下:<類名>(){}例如,對(duì)于CMeter類來說,默認(rèn)構(gòu)造函數(shù)的形式如下:CMeter() //默認(rèn)構(gòu)造函數(shù)的形式{}默認(rèn)構(gòu)造函數(shù)的目的是使下列對(duì)象定義形式合法:CMeterone; //one.CMeter();會(huì)自動(dòng)調(diào)用默認(rèn)構(gòu)造函數(shù)2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)3.默認(rèn)構(gòu)造函數(shù)2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)4.析構(gòu)函數(shù)與構(gòu)造函數(shù)相對(duì)應(yīng)的是析構(gòu)函數(shù)。析構(gòu)函數(shù)是另一個(gè)特殊的C++成員函數(shù),它只是在類名稱前面加上一個(gè)“~”符號(hào)(邏輯非),以示與構(gòu)造函數(shù)功能相反。每一個(gè)類只有一個(gè)析構(gòu)函數(shù),沒有任何參數(shù),也不返回任何值。例如:classCMeter{public: //… ~CMeter() //析構(gòu)函數(shù) { } //…}析構(gòu)函數(shù)只有在下列兩種情況下才會(huì)被自動(dòng)調(diào)用:(1)當(dāng)對(duì)象定義在一個(gè)函數(shù)體中,該函數(shù)調(diào)用結(jié)束后,析構(gòu)函數(shù)被自動(dòng)調(diào)用。(2)用new為對(duì)象分配動(dòng)態(tài)內(nèi)存,當(dāng)使用delete釋放對(duì)象時(shí),析構(gòu)函數(shù)被自動(dòng)調(diào)用。2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)4.析構(gòu)函數(shù)2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)5.應(yīng)用示例類的構(gòu)造函數(shù)和析構(gòu)函數(shù)的一個(gè)典型應(yīng)用是在構(gòu)造函數(shù)中用new為指針成員開辟獨(dú)立的動(dòng)態(tài)內(nèi)存空間,而在析構(gòu)函數(shù)中用delete釋放它們?!纠鼸x_Name】使用構(gòu)造函數(shù)和析構(gòu)函數(shù)由于“CNameone(p);”調(diào)用的是B重載構(gòu)造函數(shù),從而使得私有指針成員strName的指向等于p的指向。而p指向new開辟的內(nèi)存空間,其內(nèi)容為“DING”,一旦p指向的內(nèi)存空間刪除后,p的指向就變得不確定了,此時(shí)strName指向也不確定,所以此時(shí)運(yùn)行結(jié)果為:葺葺葺葺?2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)5.應(yīng)用示例2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)顯然,輸出的是一個(gè)無效的字符串。因此,為了保證類的封裝性,類中的指針成員所指向的內(nèi)存空間必須在類中自行獨(dú)立開辟和釋放。因此,類CName應(yīng)改成下列代碼。這樣,主函數(shù)中的代碼才會(huì)有正確的運(yùn)行結(jié)果:DING2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)顯然,輸出的是一個(gè)無效的字符2.1.5對(duì)象賦值和拷貝1.賦值在C++中,一個(gè)類的對(duì)象的初值設(shè)定可以有多種形式。例如,對(duì)于前面的類CName來說,則可有下列對(duì)象的定義方式:CNameo1; //通過A顯式默認(rèn)構(gòu)造函數(shù)設(shè)定初值CNameo2("DING"); //通過B重載構(gòu)造函數(shù)設(shè)定初值等都是合法有效的。但是若有:o1=o2; //通過賦值語句設(shè)定初值C++還常用下列形式的初始化來將另一個(gè)對(duì)象作為對(duì)象的初值:<類名><對(duì)象名1>(<對(duì)象名2>)例如:CNameo2("DING"); //A:通過構(gòu)造函數(shù)設(shè)定初值CNameo3(o2); //B:通過指定對(duì)象設(shè)定初值2.1.5對(duì)象賦值和拷貝1.賦值2.1.5對(duì)象賦值和拷貝每一個(gè)類總有一個(gè)默認(rèn)拷貝構(gòu)造函數(shù),其目的是保證B語句中對(duì)象初始化形式的合法性,其功能就等價(jià)于“CNameo3=o2;”。但語句“CNameo3(o2);”與語句“o1=o2;”一樣,也會(huì)出現(xiàn)程序終止的情況,其原因和“o1=o2;”的原因一樣。但是,若有類CData:classCData{public: CData(intdata=0) { m_nData=data; } ~CData() {} intgetData() { returnm_nData; }private: int m_nData; };2.1.5對(duì)象賦值和拷貝每一個(gè)類總有一個(gè)默認(rèn)拷貝構(gòu)造函數(shù)2.1.5對(duì)象賦值和拷貝則下列初始化形式卻都是合法有效的:CDataa(3); //通過重載構(gòu)造函數(shù)設(shè)定初值CDatab(a); //通過默認(rèn)拷貝構(gòu)造函數(shù)設(shè)定初值 //等價(jià)于CDatab=a;cout<<a.getData()<<endl; //輸出3cout<<b.getData()<<endl; //輸出32.1.5對(duì)象賦值和拷貝則下列初始化形式卻都是合法有效的2.1.5對(duì)象賦值和拷貝2.淺拷貝和深拷貝每一個(gè)C++類都有一個(gè)隱式的默認(rèn)拷貝構(gòu)造函數(shù),其目的是保證對(duì)象初始化方式的合法性,其功能是將一個(gè)已定義的對(duì)象所在的內(nèi)存空間的內(nèi)容依次拷貝到被初始化對(duì)象的內(nèi)存空間中。這種僅僅將內(nèi)存空間的內(nèi)容拷貝的方式稱為淺拷貝。3.深拷貝構(gòu)造函數(shù)拷貝構(gòu)造函數(shù)是一種比較特殊的構(gòu)造函數(shù),除遵循構(gòu)造函數(shù)的聲明和實(shí)現(xiàn)規(guī)則外,還應(yīng)按下列格式進(jìn)行定義。<類名>(參數(shù)表){}對(duì)于CName的拷貝構(gòu)造函數(shù),可有下列合法的函數(shù)原型:CName(CName&x); //x為合法的對(duì)象標(biāo)識(shí)符CName(constCName&x); CName(CName&x,…); //“…”表示還有其他參數(shù)CName(constCName&x,…); 2.1.5對(duì)象賦值和拷貝2.淺拷貝和深拷貝2.1.5對(duì)象賦值和拷貝【例Ex_CopyCon】使用拷貝構(gòu)造函數(shù)程序運(yùn)行結(jié)果如下:DINGDINGYOUHE2.1.5對(duì)象賦值和拷貝【例Ex_CopyCon】使2.1.6對(duì)象成員的初始化為提高對(duì)象初始化效率,增強(qiáng)程序的可讀性,C++允許在構(gòu)造函數(shù)的函數(shù)頭后面跟一個(gè)由冒號(hào)“:”來引導(dǎo)的對(duì)象成員初始化列表,列表中包含類中對(duì)象成員或數(shù)據(jù)成員的拷貝初始化代碼,各對(duì)象初始化之間用逗號(hào)分隔,如下列格式:<類名>::<構(gòu)造函數(shù)名>(形參表):對(duì)象1(參數(shù)表),對(duì)象2(參數(shù)表),…,對(duì)象n(參數(shù)表)

{}

對(duì)象成員初始化列表2.1.6對(duì)象成員的初始化為提高對(duì)象初始化效率,增強(qiáng)程序2.1.6對(duì)象成員的初始化先來看看第一種方式(函數(shù)構(gòu)造方式),例如。但若使用第二種方式(對(duì)象成員列表方式),即使用由冒號(hào)“:”來引導(dǎo)的對(duì)象成員初始化列表的形式,如下面的代碼:classCPoint{//…};classCRect{public: CRect(intx1,inty1,intx2,inty2) :m_ptLT(x1,y1),m_ptRB(x2,y2) {}private: CPointm_ptLT,m_ptRB;};intmain(){ CRectrc(10,100,80,250); return0;}2.1.6對(duì)象成員的初始化先來看看第一種方式(函數(shù)構(gòu)造方2.2數(shù)據(jù)共享和成員特性1.靜態(tài)數(shù)據(jù)成員與靜態(tài)變量相似,靜態(tài)數(shù)據(jù)成員是靜態(tài)存儲(chǔ)(static)的,但定義一個(gè)靜態(tài)數(shù)據(jù)成員與一般靜態(tài)變量不一樣,它必須按下列兩步進(jìn)行:(1)在類中使用關(guān)鍵字static聲明靜態(tài)數(shù)據(jù)成員。在類中聲明靜態(tài)數(shù)據(jù)成員,僅僅是說明了靜態(tài)數(shù)據(jù)成員是類中的成員這個(gè)關(guān)系,即便用該類定義對(duì)象時(shí),該靜態(tài)數(shù)據(jù)成員也不會(huì)分配內(nèi)存空間。(2)在類外為靜態(tài)數(shù)據(jù)成員分配內(nèi)存空間并初始化。類中數(shù)據(jù)成員的內(nèi)存空間是在對(duì)象定義時(shí)來分配的,但靜態(tài)數(shù)據(jù)成員的內(nèi)存空間為所有該類對(duì)象所共享,只能分配一次,因而不能通過定義類對(duì)象的方式來分配,必須在類的外部作實(shí)際定義才能為所有對(duì)象共享,其定義格式如下:<數(shù)據(jù)類型><類名>::<靜態(tài)數(shù)據(jù)成員名>=<值>2.2數(shù)據(jù)共享和成員特性1.靜態(tài)數(shù)據(jù)成員2.2數(shù)據(jù)共享和成員特性【例Ex_StaticData】靜態(tài)數(shù)據(jù)成員的使用#include<iostream.h>classCSum{public: CSum(inta=0,intb=0) //A { nSum+=a+b; } intgetSum() { returnnSum; } voidsetSum(intsum) { nSum=sum; }private: staticintnSum; //聲明靜態(tài)數(shù)據(jù)成員};intCSum::nSum=0; //靜態(tài)數(shù)據(jù)成員的實(shí)際定義和初始化intmain(){ CSumone(10,2),two; cout<<"one:sum="<<one.getSum()<<endl; cout<<"two:sum="<<two.getSum()<<endl; two.setSum(5); cout<<"one:sum="<<one.getSum()<<endl; cout<<"two:sum="<<two.getSum()<<endl; return0; }2.2數(shù)據(jù)共享和成員特性【例Ex_StaticDat2.2數(shù)據(jù)共享和成員特性程序運(yùn)行結(jié)果如下:one:sum=12two:sum=12one:sum=5two:sum=52.2數(shù)據(jù)共享和成員特性程序運(yùn)行結(jié)果如下:2.2數(shù)據(jù)共享和成員特性2.靜態(tài)成員函數(shù)在類中,靜態(tài)數(shù)據(jù)成員可以被成員函數(shù)引用,也可以被靜態(tài)成員函數(shù)所引用。但反過來,靜態(tài)成員函數(shù)卻不能直接引用類中說明的非靜態(tài)成員。假如靜態(tài)成員函數(shù)可以引用類中的非靜態(tài)成員,例如:classCSum{public:

staticvoidChangeData(intdata) { nSum=data; //錯(cuò)誤:引用類中的非靜態(tài)成員 }public: intnSum; };則當(dāng)執(zhí)行語句:CSum::ChangeData(5); //合法的靜態(tài)成員引用2.2數(shù)據(jù)共享和成員特性2.靜態(tài)成員函數(shù)2.2數(shù)據(jù)共享和成員特性【例Ex_StaticMember】靜態(tài)成員的使用程序運(yùn)行結(jié)果如下:20,40,-50,7,13,-50,7,13,20,40,2.2數(shù)據(jù)共享和成員特性【例Ex_StaticMem2.2.2友元1.友元概述類的私有型(private)數(shù)據(jù)成員和保護(hù)型(protected)數(shù)據(jù)成員只能在類中由該類的成員函數(shù)來訪問,類的對(duì)象及外部函數(shù)只能訪問類的公有型(public)成員函數(shù),類的私有和保護(hù)型數(shù)據(jù)成員只能通過類的成員函數(shù)來訪問,如圖2.1(a)所示。但是,如果在類中用friend關(guān)鍵字聲明一個(gè)函數(shù),且該函數(shù)的形參中還有該類的對(duì)象形參,這個(gè)函數(shù)便可通過形參對(duì)象或通過在函數(shù)體中定義該類對(duì)象來訪問該類的任何私有和保護(hù)型數(shù)據(jù)成員,如圖2.1(b)所示。2.2.2友元1.友元概述2.2.2友元2.友元函數(shù)友元函數(shù)可分為友元外部函數(shù)和友元成員函數(shù)。當(dāng)一個(gè)函數(shù)f是A類的友元,且f還是另一個(gè)類B的成員函數(shù)時(shí),則這樣的友元稱為友元成員函數(shù);若f不屬于任何類的成員,則這樣的友元稱為友元外部函數(shù)。通常將友元外部函數(shù)直接簡稱為友元函數(shù)。友元函數(shù)在類中定義的格式如下:friend<函數(shù)類型><函數(shù)名>(形參表){…}2.2.2友元2.友元函數(shù)2.2.2友元3.友元成員函數(shù)友元成員函數(shù)在類中定義的格式如下:friend<函數(shù)類型><類名>::<函數(shù)名>(形參表){…}【例Ex_FriendMemFun】使用友元成員函數(shù)程序運(yùn)行結(jié)果如下:Point(10,20)Rect(0,0,100,80)Point(13,23)Rect(3,3,103,83)2.2.2友元3.友元成員函數(shù)2.2.2友元4.友元類除一個(gè)類的成員函數(shù)可以聲明成另一個(gè)類的友元外,也可以將一個(gè)類聲明成另一個(gè)類的友元,稱為友元類。當(dāng)一個(gè)類作為另一個(gè)類的友元時(shí),就意味著這個(gè)類的所有成員函數(shù)都是另一個(gè)類的友元成員函數(shù)。友元類的聲明比較簡單,其格式如下:friendclass<類名>;【例Ex_ClassFriend】使用友元類程序運(yùn)行結(jié)果如下:Point(22,28)2.2.2友元4.友元類2.2.3常類型1.常對(duì)象常對(duì)象是指對(duì)象常量,定義格式如下:<類名>const<對(duì)象名>定義常對(duì)象時(shí),修飾符const可以放在類名后面,也可以放在類名前面。例如:classCOne{public: COne(inta,intb){x=a;y=b;} //…private: intx,y;};constCOnea(3,4);COneconstb(5,6);2.2.3常類型1.常對(duì)象2.2.3常類型2.常指針和常引用const的位置不同,其含義也不同,它有3種形式。第1種形式是將const放在指針變量的類型之前,表示聲明一個(gè)指向常量的指針。此時(shí),在程序中不能通過指針來改變它所指向的數(shù)據(jù)值,但可以改變指針本身的值。例如:inta=1,b=2;constint*p1=&a; //聲明指向int型常量的指針p1,指針地址為a的地址*p1=2; //錯(cuò)誤,不能更改指針?biāo)赶虻臄?shù)據(jù)值p1=&b; //正確,指向常量的指針本身的值是可以改變的2.2.3常類型2.常指針和常引用2.2.3常類型第2種形式是將const放在指針定義語句的指針名前,表示指針本身是一個(gè)常量,稱為指針常量或常指針。例如:inta=1,b=2;int*constp1=&a; //聲明指向int型常量的指針p1,指針地址為a的地址int*constp2; //錯(cuò)誤,在聲明指針常量時(shí),必須初始化*p1=2; //正確,指針?biāo)赶虻臄?shù)據(jù)值可以改變p1=&b; //錯(cuò)誤,指針常量本身的值是不可改變的第3種形式是將const在上述兩個(gè)地方都加,表示聲明一個(gè)指向常量的指針常量,指針本身的值不可改變,而且它所指向的數(shù)據(jù)的值也不能通過指針改變。例如:inta=1,b=2;constint*constpp=&a; *pp=2; //錯(cuò)誤pp=&b; //錯(cuò)誤2.2.3常類型第2種形式是將const放在指針定義語句2.2.3常類型【例Ex_ConstPara】有常參數(shù)的函數(shù)傳遞#include<iostream.h>classCOne{public: voidprint(constint*p,intn) //使用常參數(shù) { cout<<"{"<<*p; for(inti=1;i<n;i++) cout<<","<<*(p+i); cout<<"}"<<endl; }};intmain(){ intarray[6]={1,2,3,4,5,6}; COneone; one.print(array,6); return0; }程序運(yùn)行結(jié)果如下:{1,2,3,4,5,6}2.2.3常類型【例Ex_ConstPara】有常參數(shù)的2.2.3常類型3.常成員函數(shù)使用const關(guān)鍵字進(jìn)行聲明的成員函數(shù),稱為常成員函數(shù)。只有常成員函數(shù)才有資格操作常量或常對(duì)象,沒有使用const關(guān)鍵字說明的成員函數(shù)不能用來操作常對(duì)象。常成員函數(shù)說明格式如下:<類型說明符><函數(shù)名>(<參數(shù)表>)const;【例Ex_ConstFunc】常成員函數(shù)的使用程序運(yùn)行結(jié)果如下:5,4使用常成員函數(shù):20,522.2.3常類型3.常成員函數(shù)2.2.3常類型4.常數(shù)據(jù)成員類型修飾符const不僅可以說明成員函數(shù),也可以說明數(shù)據(jù)成員?!纠鼸x_ConstData】常數(shù)據(jù)成員的使用程序運(yùn)行結(jié)果如下:x=100,y=10,r=1002.2.3常類型4.常數(shù)據(jù)成員2.2.4this指針this指針是一個(gè)僅能被類的非靜態(tài)成員函數(shù)所訪問的特殊指針。當(dāng)一個(gè)對(duì)象調(diào)用成員函數(shù)時(shí),編譯器先將對(duì)象的地址賦給this指針,然后調(diào)用成員函數(shù)。例如,當(dāng)下列成員函數(shù)調(diào)用時(shí):one.copy(two);它實(shí)際上被解釋成:copy(&one,two);【例Ex_This】this指針的使用程序運(yùn)行結(jié)果如下:0,03,42.2.4this指針this指針是一個(gè)僅能被類的非靜態(tài)2.2.4this指針事實(shí)上,若成員函數(shù)的形參名與該類的成員變量名同名,則必須用this指針來顯式區(qū)分,例如:classCPoint{public: CPoint(intx=0,inty=0) { this->x=x; this->y=y; } voidOffset(intx,inty) { (*this).x+=x; (*this).y+=y; } voidPrint()const { cout<<"Point("<<x<<","<<y<<")"<<endl; }private: intx,y;};2.2.4this指針事實(shí)上,若成員函數(shù)的形參名與該類的2.3繼承和派生2.3.1單繼承從一個(gè)基類定義一個(gè)派生類可按下列格式:class<派生類名>:[<繼承方式>]<基類名>{ [<派生類的成員>]};1.公有繼承(public)公有繼承的特點(diǎn)是基類的公有成員和保護(hù)成員作為派生類的成員時(shí),它們都保持原有的狀態(tài),而基類的私有成員仍然是私有的。例如:classCStick:publicCMeter{ int m_nStickNum; //聲明一個(gè)私有數(shù)據(jù)成員public: voidDispStick(); //聲明一個(gè)公有成員函數(shù)}; //注意分號(hào)不能省略voidCStick::DispStick(){ m_nStickNum=GetPos(); //調(diào)用基類CMeter的成員函數(shù) cout<<m_nStickNum<<’’;}2.3繼承和派生2.3.1單繼承2.3.1單繼承【例Ex_PublicDerived】派生類的公有繼承示例程序運(yùn)行結(jié)果如下:CMeter:20,CStick:10CMeter:21,CStick:10CMeter:21,CStick:1111122.3.1單繼承【例Ex_PublicDerived】2.3.1單繼承2.私有繼承(private)私有繼承的特點(diǎn)是基類的公有成員和保護(hù)成員都作為派生類的私有成員,并且不能被這個(gè)派生類的子類所訪問。【例Ex_PrivateDerived】派生類的私有繼承示例程序運(yùn)行結(jié)果如下:CMeter:20,CStick:10CMeter:21,CStick:10102.3.1單繼承2.私有繼承(private)2.3.1單繼承3.保護(hù)繼承(protected)保護(hù)繼承的特點(diǎn)是基類的所有公有成員和保護(hù)成員都成為派生類的保護(hù)成員,并且只能被它的派生類成員函數(shù)或友元訪問,基類的私有成員仍然是私有的。表2.1列出了三種不同的繼承方式的基類成員和其在派生類中的特性。2.3.1單繼承3.保護(hù)繼承(protected)2.3.2派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)由于基類的構(gòu)造函數(shù)和析構(gòu)函數(shù)不能被派生類繼承,因此,若有:CMeter oA(3); 是可以的,因?yàn)镃Meter類有與之相對(duì)應(yīng)的構(gòu)造函數(shù)。而CStick oB(3);是錯(cuò)誤的,因?yàn)镃Stick類沒有對(duì)應(yīng)的構(gòu)造函數(shù)。但CStick oC;是可以的,因?yàn)镃Stick類有一個(gè)隱含的不帶參數(shù)的默認(rèn)構(gòu)造函數(shù)?!纠鼸x_ClassDerived】派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)的示例程序運(yùn)行結(jié)果如下:調(diào)用CAnimal的構(gòu)造函數(shù)!調(diào)用CCat的構(gòu)造函數(shù)!貓的名字是:noname貓的名字是:Snoopy調(diào)用CCat的析構(gòu)函數(shù)!調(diào)用CAnimal的析構(gòu)函數(shù)!2.3.2派生類的構(gòu)造函數(shù)和析構(gòu)函數(shù)由于基類的構(gòu)造函數(shù)和2.3.3多繼承多繼承下派生類的定義按下面的格式:class<派生類名>:[<繼承方式1>]<基類名1>,[<繼承方式2>]<基類名2>,…{ [<派生類的成員>]};其中的繼承方式還是前面提到的3種:public、private和protected。例如:classA{ //…};classB{ //…};classC:publicA,privateB{ //…};2.3.3多繼承多繼承下派生類的定義按下面的格式:2.3.4虛基類【例Ex_Conflict】基類成員調(diào)用的二義性程序中,派生類B1和B2都從基類A繼承,這時(shí)在派生類中就有兩個(gè)基類A的拷貝。當(dāng)編譯器編譯到“cout<<"x="<<x<<endl;”語句時(shí),因無法確定成員x是從類B1中繼承來的,還是從類B2繼承來的產(chǎn)生了二義性,從而出現(xiàn)編譯錯(cuò)誤。解決這個(gè)問題的方法之一是使用域作用運(yùn)算符“

::”來消除二義性,例如若將print函數(shù)實(shí)現(xiàn)代碼變?yōu)椋簐oidprint(){ cout<<"B1::x="<<B1::x<<endl; cout<<"B2::x="<<B2::x<<endl; cout<<"y1="<<y1<<",y2="<<y2<<endl; cout<<"z="<<z<<endl;}重新運(yùn)行,結(jié)果為:B1::x=200B2::x=400y1=100,y2=300z=5002.3.4虛基類【例Ex_Conflict】基類成員2.3.4虛基類【例Ex_VirtualBase】基類成員調(diào)用的二義性程序運(yùn)行結(jié)果如下:B1:x=0,y1=100B2:x=0,y2=300z=500B1:x=400,y1=100B2:x=400,y2=300z=500從程序中可以看出:(1)聲明一個(gè)虛基類的格式如下:virtual<繼承方式><基類名>其中,virtual是聲明虛基類的關(guān)鍵字。聲明虛基類與聲明派生類一道進(jìn)行,寫在派生類名的后面。(2)在派生類B1和B2中只有基類A的一個(gè)拷貝,當(dāng)改變成員x的值時(shí),由基類B1和B2中的成員函數(shù)輸出的成員x的值是相同的。(3)虛基類的構(gòu)造函數(shù)的調(diào)用方法與一般基類的構(gòu)造函數(shù)的調(diào)用方法是不同的。2.3.4虛基類【例Ex_VirtualBase】基2.4多態(tài)和虛函數(shù)2.4.1多態(tài)概述多態(tài)性可分為兩種:編譯時(shí)的多態(tài)性和運(yùn)行時(shí)的多態(tài)性。編譯時(shí)的多態(tài)性是通過函數(shù)或運(yùn)算符的重載來實(shí)現(xiàn)的。而運(yùn)行時(shí)的多態(tài)性是通過虛函數(shù)來實(shí)現(xiàn)的,它指在程序執(zhí)行之前,根據(jù)函數(shù)和參數(shù)還無法確定應(yīng)該調(diào)用哪一個(gè)函數(shù),必須在程序的執(zhí)行過程中,根據(jù)具體的執(zhí)行情況動(dòng)態(tài)地確定。與這兩種多態(tài)性方式相對(duì)應(yīng)的是兩種編譯方式:靜態(tài)聯(lián)編和動(dòng)態(tài)聯(lián)編。2.4多態(tài)和虛函數(shù)2.4.1多態(tài)概述2.4.2虛函數(shù)【例Ex_VirtualFunc】

虛函數(shù)的使用程序運(yùn)行結(jié)果如下:678.53982.4.2虛函數(shù)【例Ex_VirtualFunc】虛2.4.3純虛函數(shù)和抽象類聲明純虛函數(shù)的一般格式為:virtual<函數(shù)類型><函數(shù)名>(<形參表>)=0;顯然,它與一般虛函數(shù)不同的是:在純虛函數(shù)的形參表后面多了個(gè)“=0”。把函數(shù)名賦為0,本質(zhì)上是將指向函數(shù)的指針的初值賦為0。需要說明的是,純虛函數(shù)不能有具體的實(shí)現(xiàn)代碼。抽象類是指至少包含一個(gè)純虛函數(shù)的特殊的類。它本身不能被實(shí)例化,也就是說不能聲明一個(gè)抽象類的對(duì)象。必須通過繼承得到派生類后,在派生類中定義了純虛函數(shù)的具體實(shí)現(xiàn)代碼,才能獲得一個(gè)派生類的對(duì)象。【例Ex_PureVirtualFunc】純虛函數(shù)和抽象類的使用2.4.3純虛函數(shù)和抽象類聲明純虛函數(shù)的一般格式為:2.4.3純虛函數(shù)和抽象類程序運(yùn)行結(jié)果如下:6678.539878.53982.4.3純虛函數(shù)和抽象類程序運(yùn)行結(jié)果如下:2.5運(yùn)算符重載2.5.1運(yùn)算符重載函數(shù)在類中,定義一個(gè)運(yùn)算符重載函數(shù)與定義一般成員函數(shù)相類似,只不過函數(shù)名必須以operator開頭,其一般形式如下:<函數(shù)類型><類名>::operator<重載的運(yùn)算符>(<形參表>){…} //函數(shù)體【例Ex_Complex】運(yùn)算符的簡單重載程序運(yùn)行結(jié)果如下:實(shí)部=62,虛部=90實(shí)部=32,虛部=202.5運(yùn)算符重載2.5.1運(yùn)算符重載函數(shù)2.5.2運(yùn)算符重載限制在C++中,運(yùn)算符重載還有以下一些限制:(1)重載的運(yùn)算符必須是一個(gè)已有的合法的C++運(yùn)算符,如“+”、“-”、“*”、“/”、“++”等,且不是所有的運(yùn)算符都可以重載。在C++中不允許重載的運(yùn)算符有?:(條件)、.(成員)、*.(成員指針)、::(域作用符)、sizeof(取字節(jié)大?。?。(2)不能定義新的運(yùn)算符,或者說,不能為C++沒有的運(yùn)算符進(jìn)行重載。(3)當(dāng)重載一個(gè)運(yùn)算符時(shí),該運(yùn)算符的操作數(shù)個(gè)數(shù)、優(yōu)先級(jí)和結(jié)合性不能改變。(4)運(yùn)算符重載的方法通常有類的操作成員函數(shù)和友元函數(shù)兩種,但=(賦值)、()(函數(shù)調(diào)用)、[](下標(biāo))和->(成員指針)運(yùn)算符不能重載為友元函數(shù)。2.5.2運(yùn)算符重載限制在C++中,運(yùn)算符重載還有以下一2.5.3友元重載友元重載方法既可用于單目運(yùn)算符,也可以用于雙目運(yùn)算符,其一般格式如下:friend<函數(shù)類型>operator<重載的運(yùn)算符>(<形參>)//單目運(yùn)算符重載{…} //函數(shù)體friend<函數(shù)類型>operator<重載的運(yùn)算符>(<形參1,形參2>)//雙目運(yùn)算符重載{…} //函數(shù)體【例Ex_ComplexFriend】運(yùn)算符的友元重載程序運(yùn)行結(jié)果如下:實(shí)部=42,虛部=90實(shí)部=32,虛部=20實(shí)部=50,虛部=70實(shí)部=42,虛部=90實(shí)部=-12,虛部=-202.5.3友元重載友元重載方法既可用于單目運(yùn)算符,也可以2.5.4轉(zhuǎn)換函數(shù)類型轉(zhuǎn)換是將一種類型的值映射為另一種類型的值。C++的類型轉(zhuǎn)換包含自動(dòng)隱含和強(qiáng)制轉(zhuǎn)換兩種方法。轉(zhuǎn)換函數(shù)是實(shí)現(xiàn)強(qiáng)制轉(zhuǎn)換操作的手段之一,它是類中定義的一個(gè)非靜態(tài)成員函數(shù),其一般格式為:class<類名>{public: operator<類型>(); //…}【例Ex_Money】轉(zhuǎn)換函數(shù)的使用2.5.4轉(zhuǎn)換函數(shù)類型轉(zhuǎn)換是將一種類型的值映射為另一種類2.5.5賦值運(yùn)算符的重載【例Ex_Evaluate】賦值運(yùn)算符的重載程序運(yùn)行結(jié)果如下:KeyMouse2.5.5賦值運(yùn)算符的重載【例Ex_Evaluate】2.5.6自增自減運(yùn)算符的重載自增“++”和自減“--”運(yùn)算符是單目運(yùn)算符,它們又有前綴和后綴運(yùn)算符兩種。為了區(qū)分這兩種運(yùn)算符,在重載時(shí)應(yīng)將后綴運(yùn)算符視為雙目運(yùn)算符。即obj++或obj--應(yīng)被看做:obj++0或obj--0又由于這里前綴“++”中的obj必須是一個(gè)左值,因此運(yùn)算符重載函數(shù)的返回類型應(yīng)是引用而不能是對(duì)象。設(shè)類為X,當(dāng)用成員函數(shù)方法來實(shí)現(xiàn)前綴“++”和后綴“++”運(yùn)算符的重載時(shí),則可有下列一般格式:X&operator++(); //前綴++Xoperator++(int); //后綴++若用友元函數(shù)方法來實(shí)現(xiàn)前綴“++”和后綴“++”運(yùn)算符的重載時(shí),則可有下列格式:friendX&operator++(X&); //前綴++friendXoperator++(X&,int); //后綴++2.5.6自增自減運(yùn)算符的重載自增“++”和自減“--”2.5.6自增自減運(yùn)算符的重載【例Ex_Increment】前綴“++”和后綴“++”運(yùn)算符的重載程序運(yùn)行結(jié)果如下:981010122.5.6自增自減運(yùn)算符的重載【例Ex_Incremen2.6輸入/輸出流2.6.1流類和流對(duì)象C++針對(duì)流的特點(diǎn),構(gòu)造了功能強(qiáng)大的輸入/輸出流庫,它具有面向?qū)ο蟮奶匦裕淅^承結(jié)構(gòu)如圖2.2所示。2.6輸入/輸出流2.6.1流類和流對(duì)象2.6.2流的格式控制和錯(cuò)誤處理1.使用格式控制成員函數(shù)在ios類中控制輸入/輸出的成員函數(shù)有:intios::width(); //返回當(dāng)前的寬度設(shè)置intios::width(int); //設(shè)置寬度并返回上一次的設(shè)置intios::precision(); //返回當(dāng)前的精度設(shè)置intios::precision(int); //設(shè)置精度并返回上一次的設(shè)置charios::fill(); //返回當(dāng)前空位填充的字符charios::fill(char); //設(shè)置空位填充的字符并返回上一次的設(shè)置longios::setf(long); //設(shè)置狀態(tài)標(biāo)志并返回上一次的狀態(tài)標(biāo)志longios::unsetf(long); //消除狀態(tài)標(biāo)志并返回上一次的狀態(tài)標(biāo)志longios::flags(); //返回當(dāng)前的狀態(tài)標(biāo)志longios::flags(long); //設(shè)置狀態(tài)標(biāo)志并返回上一次的狀態(tài)標(biāo)志2.6.2流的格式控制和錯(cuò)誤處理1.使用格式控制成員函數(shù)2.6.2流的格式控制和錯(cuò)誤處理后面的4個(gè)成員函數(shù)都跟狀態(tài)標(biāo)志有關(guān),各種狀態(tài)值之間都是通過“|”(或運(yùn)算)組合而成的,在ios類中是一個(gè)公共的枚舉類型,各個(gè)標(biāo)志代表的含義如下:ios::skipws 跳過輸入中的空白符ios::left 輸出數(shù)據(jù)按輸出域左對(duì)齊ios::right 輸出數(shù)據(jù)按輸出域右對(duì)齊(默認(rèn))ios::internal 數(shù)據(jù)的符號(hào)左對(duì)齊,數(shù)據(jù)本身右對(duì)齊,符號(hào)和數(shù)據(jù)之間為填充字符ios::dec 轉(zhuǎn)換為十進(jìn)制形式ios::oct 轉(zhuǎn)換為八進(jìn)制形式ios::hex 轉(zhuǎn)換為十六進(jìn)制形式ios::showbase 輸出的數(shù)值前面帶有基數(shù)符號(hào)(0或0x)ios::showpoint 顯示浮點(diǎn)數(shù)的小數(shù)點(diǎn)和后面的0ios::uppercase 用大寫字母(A~F)輸出十六進(jìn)制數(shù)ios::showpos 顯示正數(shù)前面的“+”號(hào)ios::scientific 按科學(xué)記數(shù)法顯示浮點(diǎn)數(shù)ios::fixed 用定點(diǎn)格式顯示浮點(diǎn)數(shù)ios::unitbuf 輸入操作完成后立即刷新緩沖區(qū)ios::stdio 每次輸入操作完成后刷新stdout和stderr2.6.2流的格式控制和錯(cuò)誤處理后面的4個(gè)成員函數(shù)都跟狀2.6.2流的格式控制和錯(cuò)誤處理【例Ex_FormatFunc】使用格式控制成員函數(shù)程序運(yùn)行結(jié)果如下:030071+12345.70X3039+1.234568E+004********This**********is*****aTest!This********is**********aTest!*****2.6.2流的格式控制和錯(cuò)誤處理【例Ex_FormatF2.6.2流的格式控制和錯(cuò)誤處理2.使用格式算子C++提供了一些格式算子來簡化上述操作。格式算子是一個(gè)對(duì)象,可以直接用插入符或提取符來操作。C++提供的預(yù)定義格式算子如表2.2所示?!纠鼸x_Formator】使用格式算子2.6.2流的格式控制和錯(cuò)誤處理2.使用格式算子【例Ex2.6.2流的格式控制和錯(cuò)誤處理3.流的錯(cuò)誤處理在ios類中,定義了一個(gè)公有枚舉成員io_state來記錄各種錯(cuò)誤的性質(zhì):enumio_state{ goodbit =0x00, //正常 eofbit =0x01, //已達(dá)到文件尾 failbit =0x02, //操作失敗 badbit =0x04 //非法操作};在ios類中又定義了檢測上述流狀態(tài)的下列成員函數(shù):int ios::rdstate(); //返回當(dāng)前的流狀態(tài),它等于io_state中的枚舉值intios::bad(); //如果badbit位被置1,返回非0void ios::clear(int); //清除錯(cuò)誤狀態(tài)intios::eof(); //返回非0表示提取操作已到文件尾intios::fail(); //如果failbit位被置1,返回非0intios::good(); //操作正常時(shí),返回非02.6.2流的格式控制和錯(cuò)誤處理3.流的錯(cuò)誤處理2.6.2流的格式控制和錯(cuò)誤處理【例Ex_ManipError】

檢測流的錯(cuò)誤#include<iostream.h>intmain(){ inti,s; charbuf[80]; cout<<"輸入一個(gè)整數(shù):"; cin>>i; s=cin.rdstate(); cout<<"流狀態(tài)為:"<<hex<<s<<endl; while(s) { cin.clear(); cin.getline(buf,80); cout<<"非法輸入,重新輸入一個(gè)整數(shù):"; cin>>i; s=cin.rdstate(); } return0; }2.6.2流的格式控制和錯(cuò)誤處理【例Ex_ManipEr2.6.2流的格式控制和錯(cuò)誤處理程序運(yùn)行結(jié)果如下:輸入一個(gè)整數(shù):a流狀態(tài)為:2非法輸入,重新輸入一個(gè)整數(shù):abcd非法輸入,重新輸入一個(gè)整數(shù):122.6.2流的格式控制和錯(cuò)誤處理程序運(yùn)行結(jié)果如下:2.6.3使用輸入/輸出成員函數(shù)1.輸入操作的成員函數(shù)數(shù)據(jù)的輸入/輸出可以分為三大類:字符類、字符串和數(shù)據(jù)。(1)使用get和getline函數(shù)用于輸入字符或字符串的成員函數(shù)get原型如下:intget();istream&get(char&rch);istream&get(char*pch,intnCount,chardelim='\n');第1種形式是從輸入流中提取一個(gè)字符,并轉(zhuǎn)換成整型數(shù)值。第2種形式是從輸入流中提取字符到rch中。第3種形式是從輸入流中提取一個(gè)字符串并由pch返回,nCount用來指定提取字符的最多個(gè)數(shù),delim用來指定結(jié)束字符,默認(rèn)時(shí)是'\n'。函數(shù)getline原型如下:istream&getline(char*pch,intnCount,chardelim='\n');2.6.3使用輸入/輸出成員函數(shù)1.輸入操作的成員函數(shù)2.6.3使用輸入/輸出成員函數(shù)【例Ex_GetAndGetLine】get和getline的使用程序運(yùn)行結(jié)果如下:請(qǐng)輸入一個(gè)字符:A65請(qǐng)輸入一行字符串:Thisisatest!Thisisatest!請(qǐng)輸入一行字符串:ComputerComputer請(qǐng)輸入一行字符串:你今天過得好嗎?你今天過得好嗎?2.6.3使用輸入/輸出成員函數(shù)【例Ex_GetAndG2.6.3使用輸入/輸出成員函數(shù)(2)使用read函數(shù)read函數(shù)不僅可以讀取字符或字符串(稱為文本流),而且可以讀取字節(jié)流。其原型如下:istream&read(char*pch,intnCount);istream&read(unsignedchar*puch,intnCount);istream&read(signedchar*psch,intnCount);2.6.3使用輸入/輸出成員函數(shù)(2)使用read函數(shù)2.6.3使用輸入/輸出成員函數(shù)【例Ex_Read】read函數(shù)的使用#include<iostream.h>intmain(){ chardata[80]; cout<<"請(qǐng)輸入:"<<endl; cin.read(data,80); data[cin.gcount()]='\0'; cout<<endl<<data<<endl; return0; }2.6.3使用輸入/輸出成員函數(shù)【例Ex_Read】2.6.3使用輸入/輸出成員函數(shù)程序運(yùn)行結(jié)果如下:請(qǐng)輸入:12345ABCDEThisisatest!^Z

12345ABCDEThisisatest!2.6.3使用輸入/輸出成員函數(shù)程序運(yùn)行結(jié)果如下:2.6.3使用輸入/輸出成員函數(shù)2.輸出操作的成員函數(shù)ostream類中用于輸出單個(gè)字符或字節(jié)的成員函數(shù)是put和write,它們的原型如下:ostream&put(charch);ostream&write(constchar*pch,intnCount);ostream&write(constunsignedchar*puch,intnCount);ostream&write(constsignedchar*psch,intnCount);例如:chardata[80];cout<<"請(qǐng)輸入:"<<endl;cin.read(data,80);cout.write(data,80); cout<<endl;2.6.3使用輸入/輸出成員函數(shù)2.輸出操作的成員函數(shù)2.6.4提取和插入運(yùn)算符重載【例Ex_ExtractAndInsert】提取和插入運(yùn)算符的重載程序運(yùn)行結(jié)果如下:請(qǐng)輸入學(xué)生信息姓名:LiMing學(xué)號(hào):20110212三門成績:809075學(xué)生信息如下:姓名:LiMing學(xué)號(hào):20110212三門成績:80,90,752.6.4提取和插入運(yùn)算符重載【例Ex_ExtractA2.6.5文件流及其處理1.文件流概述C++提供了文件操作的文件流庫,它的體系結(jié)構(gòu)如圖2.3所示。2.6.5文件流及其處理1.文件流概述2.6.5文件流及其處理2.順序文件操作文件的順序處理是文件操作中最簡單的一種方式。在C++中打開或創(chuàng)建一個(gè)指定的文件需要下列兩個(gè)步驟:(1)聲明一個(gè)ifstream、ofstream或fstream類對(duì)象。例如:ifstreaminfile; //聲明一個(gè)輸入(讀)文件流對(duì)象ofstreamoutfile; //聲明一個(gè)輸出(寫)文件流對(duì)象fstreamiofile; //聲明一個(gè)可讀可寫的文件流對(duì)象(2)使用文件流類的成員函數(shù)打開或創(chuàng)建一個(gè)指定的文件,使得該文件與聲明的文件流對(duì)象聯(lián)系起來,這樣對(duì)流對(duì)象的操作也就是對(duì)文件的操作。例如:infile.open("file1.txt");outfile.open("file2.txt");iofile.open("file3.txt",ios::in|ios::out); 2.6.5文件流及其處理2.順序文件操作2.6.5文件流及其處理上述這兩步操作也可合為一步進(jìn)行,即在聲明對(duì)象時(shí)指定文件名。例如:ifstreaminfile("file1.txt"); ofstreamoutfile("file2.txt"); fstreamiofile("file3.txt",ios::in|ios::out); 事實(shí)上,ifstream、ofstream或fstream類構(gòu)造函數(shù)中總有一種原型和它的成員函數(shù)open功能相同。它們的函數(shù)原型如下:ifstream(constchar*szName,intnMode=ios::in,intnProt=filebuf::openprot);voidifstream::open(constchar*szName,intnMode=ios::in,intnProt=filebuf::openprot);ofstream(constchar*szName,intnMode=ios::out,intnProt=filebuf::openprot);voidofstream::open(constchar*szName,intnMode=ios::out,intnProt=filebuf::openprot);fstream(constchar*szName,intnMode,intnProt=filebuf::openprot);voidfstream::open(constchar*szName,intnMode,intnProt=filebuf::openprot);2.6.5文件流及其處理上述這兩步操作也可合為一步進(jìn)行,2.6.5文件流及其處理其中,參數(shù)szName用來指定要打開的文件名,包括路徑和擴(kuò)展名,Mode指定文件的訪問方式,表2.3列出了open函數(shù)可以使用的訪問方式?!纠鼸x_File】將文件內(nèi)容保存在另一個(gè)文件中,并將內(nèi)容顯示在屏幕上2.6.5文件流及其處理其中,參數(shù)szName用來指定要2.6.5文件流及其處理3.隨機(jī)文件操作在文件打開時(shí),文件指針指向文件的第一個(gè)字符(字節(jié))。當(dāng)然,可根據(jù)具體的讀寫操作使用C++提供的seekg和seekp函數(shù)將文件指針移動(dòng)到指定的位置。它們的原型如下:istream&seekg(longpos);istream&seekg(longoff,ios::seek_dirdir);ostream&seekp(longpos);ostream&seekp(longoff,ios::seek_dirdir);其中,pos用來指定文件指針的絕對(duì)位置。而off用來指定文件指針的相對(duì)偏移時(shí),文件指針的最后位置還依靠dir的值。dir值可以是:ios::beg 從文件流的頭部開始ios::cur 從當(dāng)前的文件指針位置開始ios::end 從文件流的尾部開始2.6.5文件流及其處理3.隨機(jī)文件操作2.6.5文件流及其處理【例Ex_FileSeek】使用seekp指定文件指針的位置程序運(yùn)行結(jié)果如下:學(xué)生信息如下:姓名:DingNing學(xué)號(hào):99005成績:80

學(xué)生信息如下:姓名:LiMing學(xué)號(hào):99002成績:92

學(xué)生信息如下:姓名:DingNing學(xué)號(hào):99005成績:802.6.5文件流及其處理【例Ex_FileSeek】

第2章C++面向?qū)ο蟪绦蛟O(shè)計(jì)

2.1類和對(duì)象2.2數(shù)據(jù)共享和成員特性2.3繼承和派生2.4多態(tài)和虛函數(shù)2.5運(yùn)算符重載2.6輸入/輸出流

第2章C++面向?qū)ο蟪绦蛟O(shè)計(jì)

2.1類和對(duì)象2.1類和對(duì)象2.1.1類的定義C++中定義類的一般格式如下:class<類名>{ private: [<私有型數(shù)據(jù)和函數(shù)>] public: [<公有型數(shù)據(jù)和函數(shù)>] protected: [<保護(hù)型數(shù)據(jù)和函數(shù)>]};<各個(gè)成員函數(shù)的實(shí)現(xiàn)>2.1類和對(duì)象2.1.1類的定義2.1.1類的定義當(dāng)類的成員函數(shù)的函數(shù)體在類的外部定義時(shí),必須由作用域運(yùn)算符“::”來通知編譯系統(tǒng)該函數(shù)所屬的類。例如:classCMeter{public: doublem_nPercent; //聲明一個(gè)公有數(shù)據(jù)成員 voidStepIt(); //聲明一個(gè)公有成員函數(shù) voidSetPos(intnPos); //聲明一個(gè)公有成員函數(shù) int GetPos() { returnm_nPos; } //聲明一個(gè)公有成員函數(shù)并定義private: intm_nPos; //聲明一個(gè)私有數(shù)據(jù)成員}; //注意分號(hào)不能省略voidCMeter::StepIt(){ m_nPos++;}voidCMeter::SetPos(intnPos){ m_nPos=nPos;}2.1.1類的定義當(dāng)類的成員函數(shù)的函數(shù)體在類的外部定義時(shí)2.1.2對(duì)象的定義與結(jié)構(gòu)類型一樣,它也有三種定義方式:聲明之后定義、聲明之時(shí)定義和一次性定義。但由于“類”比任何數(shù)據(jù)類型都要復(fù)雜得多,為了提高程序的可讀性,真正將“類”當(dāng)成一個(gè)密閉、“封裝”的盒子(接口),在程序中應(yīng)盡量在對(duì)象的聲明之后定義方式,并按下列格式進(jìn)行:<類名><對(duì)象名表>一個(gè)對(duì)象的成員就是該對(duì)象的類所定義的數(shù)據(jù)成員(成員變量)和成員函數(shù)。訪問對(duì)象的成員變量和成員函數(shù)和訪問變量和函數(shù)的方法是一樣的,只不過要在成員前面加上對(duì)象名和成員運(yùn)算符“.”,其表示方式如下:<對(duì)象名>.<成員變量><對(duì)象名>.<成員函數(shù)>(<參數(shù)表>)例如:myMeter.m_nPercent,myMeter.SetPos(2),Meters[0].StepIt();2.1.2對(duì)象的定義與結(jié)構(gòu)類型一樣,它也有三種定義方式:2.1.2對(duì)象的定義若對(duì)象是一個(gè)指針,則對(duì)象的成員訪問形式如下:<對(duì)象指針名>-><成員變量><對(duì)象指針名>-><成員函數(shù)>(<參數(shù)表>)“->”是一個(gè)表示成員的運(yùn)算符,它與“.”運(yùn)算符的區(qū)別是:“->”用來表示指向?qū)ο蟮闹羔樀某蓡T,而“.”用來表示一般對(duì)象的成員。2.1.2對(duì)象的定義若對(duì)象是一個(gè)指針,則對(duì)象的成員訪問形2.1.3類作用域和成員訪問權(quán)限1.類名的作用域如果在類聲明之前就需要使用該類名定義對(duì)象,則必須用下列格式在使用前進(jìn)行提前聲明(注意,類的這種形式的聲明可以在相同作用域中出現(xiàn)多次):class<類名>;例如:classCOne; //將類COne提前聲明classCOne; //可以聲明多次classCTwo{ //…private: COnea; //數(shù)據(jù)成員a是已定義的COne類對(duì)象};classCOne{ //…};2.1.3類作用域和成員訪問權(quán)限1.類名的作用域2.1.3類作用域和成員訪問權(quán)限2.類中成員的可見性(1)在類中使用成員時(shí),成員聲明的前后不會(huì)影響該成員在類中的使用,這是類作用域的特殊性。例如:classA{ voidf1() {

f2(); //調(diào)用類中的成員函數(shù)f2 cout<<a<<endl; //使用類中的成員變量a } voidf2(){} inta;};2.1.3類作用域和成員訪問權(quán)限2.類中成員的可見性2.1.3類作用域和成員訪問權(quán)限(2)由于類的成員函數(shù)可以在類體外定義,因而此時(shí)由“類名::”指定開始一直到函數(shù)體最后一個(gè)花括號(hào)為止的范圍也是該類作用域的范圍。例如:classA{ voidf1(); //…};voidA::f1(){ //…}則從A::開始一直到f1函數(shù)體最后一個(gè)花括號(hào)為止的范圍都是屬于類A的作用域。(3)在同一個(gè)類的作用域中,不管成員具有怎樣的訪問權(quán)限,都可在類作用域中使用,而在類作用域外卻不可使用。例如:classA{public: inta; //…};a=10; //錯(cuò)誤,不能在A作用域外直接使用類中的成員2.1.3類作用域和成員訪問權(quán)限(2)由于類的成員函數(shù)可2.1.3類作用域和成員訪問權(quán)限3.類外對(duì)象成員的可見性對(duì)于訪問權(quán)限public、private和protected來說,只有在子類中或用對(duì)象來訪問成員時(shí),它們才會(huì)起作用。在用類外對(duì)象來訪問成員時(shí),只能訪問public成員,而對(duì)private和protected均不能訪問。2.1.3類作用域和成員訪問權(quán)限3.類外對(duì)象成員的可見性2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)1.構(gòu)造函數(shù)C++規(guī)定,一個(gè)類的構(gòu)造函數(shù)必須與相應(yīng)的類同名,它可以帶參數(shù),也可以不帶參數(shù),與一般的成員函數(shù)定義相同,可以重載,也可以有默認(rèn)的形參值。例如:classCMeter{public: CMeter(intnPos) //帶參數(shù)的構(gòu)造函數(shù) { m_nPos=nPos; } //…}這樣若有:CMeteroMeter(10),oTick(20);2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)1.構(gòu)造函數(shù)2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)2.對(duì)構(gòu)造函數(shù)的幾點(diǎn)說明(1)構(gòu)造函數(shù)的約定使系統(tǒng)在生成類的對(duì)象時(shí)自動(dòng)調(diào)用。同時(shí),指定對(duì)象括號(hào)里的參數(shù)就是構(gòu)造函數(shù)的實(shí)參,例如,oMeter(10)就是oMeter.CMeter(10)。故當(dāng)構(gòu)造函數(shù)重載及設(shè)定構(gòu)造函數(shù)默認(rèn)形參值時(shí),要避免出現(xiàn)二義。CPerson(char*str,floath=170,floatw=130) //A{ strcpy(name,str); height=h; weight=w;}CPerson(char*str) //B{ strcpy(name,str);}2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)2.對(duì)構(gòu)造函數(shù)的幾點(diǎn)說明2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)(2)定義的構(gòu)造函數(shù)不能指定其返回值的類型,也不能指定為void類型。事實(shí)上,由于構(gòu)造函數(shù)主要用于對(duì)象數(shù)據(jù)成員的初始化,因而無須返回函數(shù)值,也就無須有返回類型。(3)若要用類定義對(duì)象,則構(gòu)造函數(shù)必須是公有型成員函數(shù),否則類無法實(shí)例化(即無法定義對(duì)象)。若類僅用于派生其他類,則構(gòu)造函數(shù)可定義為保護(hù)型成員函數(shù)。2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)(2)定義的構(gòu)造函數(shù)不能指定2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)3.默認(rèn)構(gòu)造函數(shù)實(shí)際上,在類定義時(shí),如果沒有定義任何構(gòu)造函數(shù),則編譯自動(dòng)為類隱式生成一個(gè)不帶任何參數(shù)的默認(rèn)構(gòu)造函數(shù),由于函數(shù)體是空塊,因此默認(rèn)構(gòu)造函數(shù)不進(jìn)行任何操作,僅僅為了滿足對(duì)象創(chuàng)建時(shí)的語法需要。其形式如下:<類名>(){}例如,對(duì)于CMeter類來說,默認(rèn)構(gòu)造函數(shù)的形式如下:CMeter() //默認(rèn)構(gòu)造函數(shù)的形式{}默認(rèn)構(gòu)造函數(shù)的目的是使下列對(duì)象定義形式合法:CMeterone; //one.CMeter();會(huì)自動(dòng)調(diào)用默認(rèn)構(gòu)造函數(shù)2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)3.默認(rèn)構(gòu)造函數(shù)2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)4.析構(gòu)函數(shù)與構(gòu)造函數(shù)相對(duì)應(yīng)的是析構(gòu)函數(shù)。析構(gòu)函數(shù)是另一個(gè)特殊的C++成員函數(shù),它只是在類名稱前面加上一個(gè)“~”符號(hào)(邏輯非),以示與構(gòu)造函數(shù)功能相反。每一個(gè)類只有一個(gè)析構(gòu)函數(shù),沒有任何參數(shù),也不返回任何值。例如:classCMeter{public: //… ~CMeter() //析構(gòu)函數(shù) { } //…}析構(gòu)函數(shù)只有在下列兩種情況下才會(huì)被自動(dòng)調(diào)用:(1)當(dāng)對(duì)象定義在一個(gè)函數(shù)體中,該函數(shù)調(diào)用結(jié)束后,析構(gòu)函數(shù)被自動(dòng)調(diào)用。(2)用new為對(duì)象分配動(dòng)態(tài)內(nèi)存,當(dāng)使用delete釋放對(duì)象時(shí),析構(gòu)函數(shù)被自動(dòng)調(diào)用。2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)4.析構(gòu)函數(shù)2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)5.應(yīng)用示例類的構(gòu)造函數(shù)和析構(gòu)函數(shù)的一個(gè)典型應(yīng)用是在構(gòu)造函數(shù)中用new為指針成員開辟獨(dú)立的動(dòng)態(tài)內(nèi)存空間,而在析構(gòu)函數(shù)中用delete釋放它們?!纠鼸x_Name】使用構(gòu)造函數(shù)和析構(gòu)函數(shù)由于“CNameone(p);”調(diào)用的是B重載構(gòu)造函數(shù),從而使得私有指針成員strName的指向等于p的指向。而p指向new開辟的內(nèi)存空間,其內(nèi)容為“DING”,一旦p指向的內(nèi)存空間刪除后,p的指向就變得不確定了,此時(shí)strName指向也不確定,所以此時(shí)運(yùn)行結(jié)果為:葺葺葺葺?2.1.4構(gòu)造函數(shù)和析構(gòu)函數(shù)5.應(yīng)用示例2.1.4

溫馨提示

  • 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ì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論