版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第十八章多態(tài)一般含義是,某一論域中的一個元素可以有多種解釋。具體到程序語言,則有以下兩個含義:相同的語言結(jié)構(gòu)可以代表不同類型的實體(一名多用);相同的語言結(jié)構(gòu)可以對不同類型的實體進(jìn)行操作(類屬)。多態(tài)的作用是提高語言的靈活性、實現(xiàn)高層軟件的復(fù)用。
面向?qū)ο蟪绦蛟O(shè)計具有一種獨特的多態(tài):一個公共的消息集可以發(fā)送到不同種類的對象,從而得到不同的處理。多態(tài)函數(shù)名重載在同一個作用域中,相同的標(biāo)識符可以用于定義不同的函數(shù),但要求這些函數(shù)應(yīng)擁有不同的參數(shù)(參數(shù)類型或個數(shù))。
函數(shù)重載主要用于定義多個功能相同而參數(shù)不同的函數(shù)。
在C++中,對重載函數(shù)的綁定采用靜態(tài)綁定,由編譯器根據(jù)實參與形參的個數(shù)與類型匹配來實現(xiàn).多態(tài)運算符重載需要性
提高語言的靈活性和可擴充性,實現(xiàn)多態(tài)。語言提供的操作符只定義了對基本數(shù)據(jù)類型的運算,操作符重載機制提供用已有的操作符來對自己定義的數(shù)據(jù)類型進(jìn)行操作的手段,從而使得程序更容易理解。classComplex{doublereal,imag;public:Complex(){real=0;imag=0;}Complex(doubler,doublei){real=r;imag=i;}Complexadd(Complex&x);};Complexa(1,2),b(3,4),c; c=a.add(b);多態(tài)上述程序段實現(xiàn)了兩個復(fù)數(shù)的相加操作,如果能表示成:a=b+c,將會更加容易理解。利用操作符重載機制可以把上述的Complex類重新定義成:classComplex{doublereal,imag;public: Complex(){real=0;imag=0;} Complex(doubler,doublei){real=r;imag=i;}
Complexoperator+(Complex&x) {Complextemp; temp.real=real+x.real; temp.imag=imag+x.imag; returntemp; }};多態(tài) classComplex {doublereal,imag; public: Complex(){real=0;imag=0;} Complex(doubler,doublei){real=r;imag=i;}friendComplexoperator+(Complex&c1,Complex&c2); };
Complexoperator+(Complex&c1,Complex&c2){Complextemp; temp.real=c1.real+c2.real; temp.imag=c1.imag+c2.imag; returntemp;} …... Complexa(1,2),b(3,4),c; c=a+b;多態(tài)可重載的操作符
除..*
::
?:四個外,其它操作符都可以重載。操作符重載的基本原則操作符的重載或者作為類的成員函數(shù)或者是帶有類參數(shù)的全局函數(shù)。遵循已有操作符的語法:單目/雙目,優(yōu)先級,結(jié)合性。遵循已有操作符的語義(不是必需的)。除操作符=外,重載的操作符可以繼承。多態(tài)雙目操作符重載
需要兩個參數(shù),可以作為類成員函數(shù)或全局(友元)函數(shù)。作為類成員函數(shù)第一個參數(shù)是this,它是隱含的,不需要給出,只需要給出第二個參數(shù)。格式: 聲明
<rettype>operator#(<arg>);
定義
<rettype>
<classname>::operator#(<arg>) {…}多態(tài)使用
<classname>a,b;a#b,或,a.operator#(b)作為全局(友元)函數(shù)
需要給出兩個參數(shù),其中至少有一個類型為類或類的引用參數(shù)。格式聲明class<classname>{… friend<rettype>operator#(<arg1>,<arg2>);};多態(tài)定義
<rettype>
operator#(<arg1>,<arg2>){…}限制
=,(),[]和不能作為全局(友元)函數(shù)重載。作為類成員函數(shù)和作為全局友元函數(shù)的區(qū)別成員函數(shù)只需給一個參數(shù),而友元函數(shù)必須給兩個參數(shù)有時必須用全局友元函數(shù)重載操作符。多態(tài)obj+1010+objclassCL{intcount;public: friendCLoperator+(inti,CL&a); friendCLoperator+(CL&a,inti);}多態(tài)單目操作符重載需要一個參數(shù)。作為類成員函數(shù)參數(shù)是this,它是隱含的,不需要給出。格式:聲明class<classname>{…
<rettype>operator#();};多態(tài)定義
<rettype><classname>::operator#(){…}使用<classname>a;#a,或,a.operator#()問題:怎么處理a++?
classCounter{intvalue;public:Counter(){value=0;}Counter&operator++()//++a{value++;return*this;}Counteroperator++(int)//a++{Countertemp=*this;value++;returntemp;}}如果未定義第二個重載,則a++用第一個定義;如果定義了第二個重載,則a++用第二個定義注意:上述的第一個重載返回的是引用(為什么?)。多態(tài)作為友元函數(shù)
需要給出一個參數(shù)。格式:聲明
class
<classname>
{…
friend
<rettype>
operator#(<arg>);
};
定義
<rettype><classname>::operator#(<arg>)
{…}多態(tài)幾個特殊操作符的重載賦值操作符=
每個類都有一個默認(rèn)賦值操作符=函數(shù),其行為是:逐個成員賦值(member-wiseassignment),對包含有對象成員的類,該定義是遞歸的。有時,默認(rèn)賦值操作符=函數(shù)不能滿足需要(特別是類包含指針成員時),這時需要重載=。賦值操作符重載不能繼承。多態(tài)classA { intx,y; char*p; public: A&operator=(A&a) {x=a.x;y=a.y; delete[]p; p=newchar[strlen(a.p)+1]; strcpy(p,a.p); return*this; } };如果上述類A中沒有給出重載的=,則對于下面的語句,將會使得a.p和b.p指向同一塊區(qū)域。
Aa,b; a=b;多態(tài)函數(shù)調(diào)用運算符()classA {… public: intoperator()(intx,char*p); }; … Aa; a(i,”abcd”);
函數(shù)調(diào)用運算符()的重載對提高程序的可讀性沒有好處,盡量少用。多態(tài)數(shù)組元素訪問運算符[]
classstring {char*p; public: string(char*p1){p=newchar[strlen(p1)+1];strcpy(p,p1);} char&operator[](inti){returnp[i];} } … strings(“abcd”); cout<<s[2];多態(tài)成員訪問運算符
為二元運算符,如果重載則當(dāng)作一元操作符來用。classA{intx,y;public:f();g();};classB{Aa;intcount;public:B(){count=0;}A*operator->(){count++;return&a;}intnum_of_a_access(){returncount;}f();};多態(tài)Bb;b->f();//等價于:b.operator->()->f();即訪問的是b.a.f()b->g();//等價于:b.operator->()->g();即訪問的是
b.a.g()
//上述兩個->是重載的->。cout<<b.num_of_a_access();//顯示對對象b.a的訪問次數(shù)B*p=&b;p->f();//訪問的是b.f();p->g();//Error,b沒有g(shù)()。//上述兩個->是未重載的->。仔細(xì)體會這個例子多態(tài)類型轉(zhuǎn)換運算符(int,char,…,或自己定義的類名)
classA {intx,y; public:...... operatorint(){returnx+y;} }; … Aa; inti=1,z; z=i+(int)a;多態(tài)動態(tài)存貯分配與去配運算符new
與delete
由于new與delete將調(diào)用系統(tǒng)的存儲管理來進(jìn)行動態(tài)內(nèi)存的分配與去配,往往效率不高。程序可以自己來管理內(nèi)存以提高效率,基本做法是:程序首先調(diào)用系統(tǒng)存儲分配申請一塊較大的內(nèi)存,然后,在該內(nèi)存中進(jìn)行自己的存儲分配與去配,這可以通過重載new與delete來實現(xiàn)。重載new
在定義一個類A時,提供一個具有下述原型的成員函數(shù):void*operatornew(size_tsize,…);
該函數(shù)的名為operatornew,返回類型必須為void*,第一個參數(shù)類型為size_t(unsignedint),其它參數(shù)可有可無。多態(tài)當(dāng)動態(tài)創(chuàng)建A類對象時,系統(tǒng)自動計算對象的大小并把它傳給size。如果重載的new有其它參數(shù),則動態(tài)對象的創(chuàng)建采用以下形式:A*p=new(…)A;
這里,…表示傳給new的其它實參。
new的重載可以有多個,在某類中重載了new后,通過new動態(tài)創(chuàng)建該類的對象時將不再調(diào)用內(nèi)置的(預(yù)定義的)new操作來分配內(nèi)存空間,而是調(diào)用自己重載的new操作。多態(tài)重載delete
在定義一個類A時,提供一個具有下述原型的成員函數(shù):voidoperatordelete(void*p,size_tsize);
該函數(shù)的名為operatordelete,返回類型必須為void,第一個參數(shù)類型為void*,第二個參數(shù)可有可無,如果有,則必須是size_t類型。當(dāng)用delete撤消一個對象時,系統(tǒng)把該對象的地址傳給重載的delete,如果重載的delete有第二個參數(shù),則系統(tǒng)會把欲撤消的對象的大小傳給之。
delete的重載只能有一個,在某類中重載了delete后,通過delete撤消對象時將不再調(diào)用內(nèi)置的(預(yù)定義的)delete操作,而是調(diào)用自己重載的delete操作。重載的new和delete是靜態(tài)成員,也遵循類的訪問控制,并且可以繼承。多態(tài)-虛函數(shù)類型相容
C++把類看作類型,有了類型就要考慮類型相容問題,其中包括賦值相容問題,即a和b是什么類型時,a=b的賦值操作是合法的.在C++中允許把派生類對象賦值給基類對象,這時對象的身份已發(fā)生變化,對象已從派生類變成了基類,原屬于派生類的屬性已不存在。在C++中還允許基類的引用或指針可以引用或指向派生類對象,這時,引用或指向的對象身份沒有發(fā)生變化。classA{intx,y;public:f();};classB:publicA{intz;public: f(); g();};Aa;Bb;a=b;//OK,b=a;//Errora.f();//A::f()A&r_a=b; //OKA*p_a=&b; //OKB&r_b=a; //ErrorB*p_b=&a; //Error把派生類對象賦值給基類對象基類的引用或指針可以引用或指向派生類對象func1(A&a){…a.f();…}func2(A*pa){…pa->f();…}func1(b);func2(&b);在func1和func2中的a.f()和pa->f()調(diào)用的是A類中的f還是B類中的f?多態(tài)-虛函數(shù)
對上述問題存在兩種解決方案:前期綁定:在編譯時刻,根據(jù)a和pa的靜態(tài)類型來決定f屬于哪一個類。由于a和pa的靜態(tài)類型分別是A&和A*,所以確定f是A::f。后期綁定:在運行時刻,根據(jù)a和pa實際引用和指向的對象類型(動態(tài)類型)來確定f屬于哪一個類。在func1(a)和func2(&a)的調(diào)用中,f是A::f;在func1(b)和func2(&b)的調(diào)用中,f是B::f。C++是一個注重程序效率的語言,而采用后期綁定的程序效率是不高的,因此,C++中默認(rèn)的綁定方式是前期綁定,如果需要后期綁定,必須由程序員在程序中顯式指出。多態(tài)-虛函數(shù)虛函數(shù)為了對上述的func1和func2中的f調(diào)用進(jìn)行后期綁定,必須在類A的定義中把f聲明為虛函數(shù)(virtual)。 classA {… public: virtualf(); };
這樣,func1和func2中的a.f()和pa->f()將在運行時刻根據(jù)a和pa實際引用和指向的對象類型來確定f屬于哪一個類。多態(tài)-虛函數(shù)一旦在基類中指定某成員函數(shù)為虛函數(shù),那么,不管在派生類中是否給出virtual聲明,派生類(派生類的派生類,…)中對其重定義的成員函數(shù)均為虛函數(shù)。限制類的成員函數(shù)才可以是虛函數(shù)。靜態(tài)成員函數(shù)不能是虛函數(shù)。內(nèi)聯(lián)成員函數(shù)不能是虛函數(shù)。構(gòu)造函數(shù)不能是虛函數(shù)。析構(gòu)函數(shù)可以(往往)是虛函數(shù)。多態(tài)-虛函數(shù)classA{public: A(){f();} virtualf(); g(); h(){f();g();} }; classB:publicA {public: f(); g(); }; …Bb;A*p=&b;p->f();p->g();p->h(); //調(diào)用b.B::B(),b.A::A(),b.A::f//調(diào)用b.B::f//調(diào)用b.A::g//調(diào)用b.A::h,b.B::f,b.A::g多態(tài)-虛函數(shù)純虛函數(shù)和抽象類純虛函數(shù)只給出了函數(shù)聲明沒給出實現(xiàn)的虛成員函數(shù)稱為純虛函數(shù),聲明時在函數(shù)原型的后面加上=0,例如virtualintf()=0;抽象類包含純虛函數(shù)的類稱為抽象類,抽象類不能用于創(chuàng)建對象。
多態(tài)-虛函數(shù) classA//抽象類 {… public: virtualintf()=0;//純虛函數(shù) }; ...... Aa;//Error抽象類的作用在于為派生類提供一個框架:派生類應(yīng)提供抽象基類的所有成員函數(shù)的實現(xiàn)。多態(tài)-虛函數(shù)抽象類的使用FigureRectangleEllipseLinevirtualdisplay()=0;displaydisplaydisplayFigure*a[100];a[0]=newRectangle();a[1]=newEllipse();a[2]=newLine();…for(inti=0;i<num_of_figures;i++)a[i]->display();多態(tài)-虛函數(shù)虛函數(shù)后期綁定的實現(xiàn)
classA{intx,y;public:virtualf();virtualg();h();};classB:publicA{intz;public:f();h();};Aa;Bb;A*p;對于每一個類,如果有虛函數(shù)(包括從基類繼承來的),則編譯器將會為其創(chuàng)建一個虛函數(shù)表(vtable),表中記錄了類中所有虛函數(shù)的入口地址。當(dāng)創(chuàng)建一個對象時,在所創(chuàng)建對象的內(nèi)存空間中有一個指針指向該對象所屬類的虛函數(shù)表。B::fA::gbxyzB_vtablep->f()(*(*p))(p)(**((char*)p-4))(p)axyA::fA::gA_vtable多態(tài)-模板模板類屬性用于實現(xiàn)參數(shù)化模塊,即,給程序模塊加上類型參數(shù),使其能對不同類型的數(shù)據(jù)實施相同的操作,它是多態(tài)的一種形式。在C++中,類屬性主要體現(xiàn)在類屬函數(shù)和類屬類中。類屬函數(shù)一個函數(shù)對不同類型的數(shù)據(jù)完成相同的操作。多態(tài)-模板宏實現(xiàn)#definemax(a,b)((a)>(b)?(a):(b))
不足之處:只能實現(xiàn)簡單的功能,并且存在不作類型檢查以及重復(fù)計算等問題。函數(shù)重載intmax(int,int);doublemax(double,double);Amax(A,A);
不足之處:需要定義的重載函數(shù)太多,如果定義不全會有問題。多態(tài)-模板指針實現(xiàn)
例如編寫一個排序(sort)函數(shù),使其能對各種數(shù)據(jù)進(jìn)行排序(整型數(shù)序列、浮點數(shù)序列以及某個類的對象序列等)。
voidsort(void*base,//需排序的數(shù)據(jù)首地址 unsignedintcount,//數(shù)據(jù)元素的個數(shù)unsignedintelement_size,//數(shù)據(jù)元素的大小int(*cmp)(void*,void*)//比較兩個數(shù)據(jù)元素
//大小的函數(shù)指針 )
不足之處:需要定義額外的參數(shù),并且有大量的指針運算,使得實現(xiàn)起來麻煩、可讀性差。多態(tài)-模板函數(shù)模板上述的排序用函數(shù)模板來實現(xiàn)。template<classT>voidsort(Telements[],unsignedintcount){//取第i個元素elements[i]//比較第i個和第j個元素的大小elements[i]<elements[j]//交換第i個和第j個元素
Ttemp=elements[i]; elements[i]=elements[j]; elements[j]=temp;}...…inta[100];sort(a,100);doubleb[200];sort(b,200);Ac[300];sort(c,300);類A中需重載操作符:<和=,給出拷貝構(gòu)造函數(shù)多態(tài)-模板函數(shù)模板定義了一類重載的函數(shù),使用函數(shù)模板所定義的函數(shù)(模板函數(shù))時,編譯系統(tǒng)會自動把函數(shù)模板實例化。模板的參數(shù)可以有多個,用逗號分隔它們,如:template<classT1,classT2>voidf(T1a,T2b){...…}模板也可以帶普通參數(shù),它們須放在類型參數(shù)的后面,調(diào)用時需顯式實例化,如: template<classT,intsize> voidf(Ta) {Ttemp[size];......} voidmain() {f<int,10>(1);}多態(tài)-模板需要把函數(shù)模板與函數(shù)重載結(jié)合起來用template<classT>Tmax(Ta,Tb){returna>b?a:b;} … intx,y,z; doublel,m,n; z=max(x,y); l=max(m,n);問題:max(x,m)如何處理?定義一個max的重載函數(shù):doublemax(inta,doubleb){returna>b?a:b;}多態(tài)-模板類屬類類定義帶有類型參數(shù)定義一個棧類,其元素類型可以變化。template<classT>classStack{Tbuffer[100];public:voidpush(Tx);
Tpop();};template<classT>voidStack<T>::push(Tx){…}template<classT>TStack<T>::pop(){…}……Stack<int>st1;//顯式實例化Stack<double>st2;例:定義一個棧類。classStack{intbuffer[100];public:voidpush(intx);intpop();};voidStack::push(intx){…}intStack::pop(){…}……Stackst1;多態(tài)-模板類模板定義了若干個類,類模板的實例化是顯式的。
類模板的參數(shù)可以有多個,其中包括普通參數(shù),用逗號分隔它們。并且普通參數(shù)須放在類型參數(shù)的后面。類模板不能嵌套(局部類模板)。類模板中的靜態(tài)成員僅屬于實例化后的類(模板類),不同實例之間不存在共享。多態(tài)-模板例:定義不同大小的棧模板
template<classT,intsize> classStack {Tbuffer[size]; public: voidpush(Tx); Tpop(); }; template<classT,intsize>voidStack<T,size>::push(Tx){…} template<classT,intsize> TStack<T,size>::pop(){…} …… Stack<int,100>st1; Stack<double,200>st2;多態(tài)-模板模板也是一種代碼復(fù)用機制模板提供了代碼復(fù)用。在使用模板時首先要實例化,即生成一個具體的函數(shù)或類。函數(shù)模板的實例化是隱式實現(xiàn)的,即由編譯系統(tǒng)根據(jù)對具體模板函數(shù)(實例化后的函數(shù))的調(diào)用來進(jìn)行相應(yīng)的實例化,而類模板的實例化是顯式進(jìn)行的,在創(chuàng)建對象時由程序指定。一個模板有很多實例,是否實例化模板的某個實例由使用點來決定,如果未使用到一個模板的某個實例,則編譯系統(tǒng)不會生成相應(yīng)實例的代碼。在C++中,由于模塊是分別編譯的,如果在模塊A中要使用模塊B中定義的一個模板的某個實例,而在模塊B中未使用這個實例,則模塊A無法使用這個實例,除非在模塊A中也定義了相應(yīng)的模板。因此模板是基于源代碼復(fù)用,而不是目標(biāo)代碼復(fù)用。多態(tài)-模板#include"file1.h"template<classT>voidS<T>::f(){…}template<classT>Tmax(Tx,Ty){returnx>y?x:y;}voidmain(){inta,b;max(a,b);S<int>x;x.f();}template<classT>classS{Ta;public:voidf();};#include"file1.h"externdoublemax(double,double);voidsub(){max(1.1,2.2);//ErrorS<float>x;x.f();//Error}file1.cppfile1.hfile2.cpp輸入/輸出(I/O)輸入/輸出(I/O)是程序的一個重要組成部分,也是一個不容易規(guī)范化的語言機制,它要依賴于不同的操作系統(tǒng),是平臺有關(guān)的。輸入/輸出不是C++語言的成分,而是由具體的實現(xiàn)(編譯器)作為函數(shù)庫或類庫來提供。C++的設(shè)計者對I/O提出了一種方案,雖然它不屬于C++的標(biāo)準(zhǔn)范疇,但大多數(shù)的實現(xiàn)也都實現(xiàn)了這個方案,因此,它成了默認(rèn)的標(biāo)準(zhǔn)。輸入/輸出(I/O)在C++中,輸入/輸出操作是基于一種字節(jié)流來實現(xiàn)的。在進(jìn)行輸入操作時,數(shù)據(jù)逐個字節(jié)地從外部流入到內(nèi)部(計算機中);在進(jìn)行輸出操作時,數(shù)據(jù)逐個字節(jié)地從內(nèi)部流出到外部。為了方便使用,在C++的函數(shù)庫和類庫中,除了提供基于字節(jié)的I/O操作外,還提供了C++基本數(shù)據(jù)類型數(shù)據(jù)的I/O操作。另外,也可以對類庫中I/O流類的一些操作進(jìn)行重載,使其能對自定義類的對象進(jìn)行I/O操作。輸入/輸出(I/O)基于函數(shù)庫的I/O(面向過程)
用C++以面向過程風(fēng)范進(jìn)行程序設(shè)計時,可使用C++函數(shù)庫中的函數(shù)實現(xiàn)輸入/輸出。這些函數(shù)分別用于控制臺、文件和字符串變量的I/O??刂婆_I/O輸出
#include<stdio.h>
putchar(intch);//ch中的字符輸出到顯示器 puts(constchar*p);//p所指向的字符串輸出到顯示器
輸入/輸出(I/O)printf(constchar*format[,<參數(shù)表>]);
其中,format指向一個格式字符串,該字符串包含兩類字符:普通顯示字符和控制字符。普通字符將顯示在顯示器上,控制字符用于控制<參數(shù)表>中的數(shù)據(jù)的顯示格式。<參數(shù)表>中的參數(shù)為表達(dá)式。 inti=1,j=2; printf("i=%d,j=%d\n",i,j); 結(jié)果為:i=1,j=2輸入/輸出(I/O)控制字符以%開始,常用的控制符號有:%c 字符%d 十進(jìn)制整型數(shù)%u 無符號十進(jìn)制整型數(shù)%o 八進(jìn)制整型數(shù)%x 十六進(jìn)制整型數(shù)%s 字符串%f 浮點數(shù),包括float和double,格式為: dddd.dddd%e 浮點數(shù),包括float和double,格式為: [-]d.dddde[+/-]ddd輸入/輸出(I/O)輸入#include<stdio.h>
intgetchar();//從鍵盤輸入一個字符返回。char*gets(constchar*p);//從鍵盤輸入一個字符串 放入p所指向的內(nèi)存空間。scanf(constchar*format[,<參數(shù)表>]);
其中,format指向一個格式字符串,該字符串包含兩類字符:普通顯示字符和控制字符(與printf類似)。普通字符用于與輸入字符進(jìn)行匹配,控制字符用于控制<參數(shù)表>中的數(shù)據(jù)的輸入格式。<參數(shù)表>中的參數(shù)為變量的地址。
inti,j; scanf("i=%d,j=%d",&i,&j);輸入/輸出(I/O)另外,有些C++編譯器還提供了一些特殊的函數(shù)(<conio.h>),如:
intgetch();//不帶緩沖的輸入,不回顯 intgetche();//不帶緩沖的輸入,回顯文件I/O輸出#include<stdio.h>FILE*fopen(constchar*filename,constchar*mode);
其中,mode可以是:"w":打開一個空文件用于寫操作,如果文件已存在,則首先清空之。"a":打開一個文件用于添加(從文件末尾)操作。另外,在w或a的后面還可以加上t或b,以區(qū)別文本或二進(jìn)制文件。輸入/輸出(I/O)intfputc(intc,FILE*stream);intfputs(constchar*string,FILE*stream);intfprintf(FILE*stream, constchar*format[,argument]...);size_tfwrite(constvoid*buffer,size_tsize,size_tcount,FILE*stream);fclose(FILE*stream);輸入
#include<stdio.h>FILE*fopen(constchar*filename,constchar*mode);其中,mode可以是:"r":打開一個文件用于讀操作。另外,在r的后面還可以加上t或b,以區(qū)別文本或二進(jìn)制文件。輸入/輸出(I/O)intfgetc(FILE*stream); char*fgets(char*string,intn,FILE*stream); intfscanf(FILE*stream,constchar*format[,argument]...); size_tfread(constvoid*buffer,size_tsize,size_tcount,FILE*stream);fclose(FILE*stream);輸入/輸出
#include<stdio.h>
FILE
*fopen(
const
char
*filename,
const
char
*mode
); 其中,mode可以是:"r+":打開一個文件用于讀/寫操作,文件必須存在。"w+":打開一個空文件用于讀/寫操作,如果文件已存在,則首先清空之。 "a+":打開一個文件用于讀/添加操作。 另外,在a+、w+或a+的后面還可以加上t或b,以區(qū)別文本或二進(jìn)制文件。輸入/輸出(I/O)隨機輸入/輸出intfseek(FILE*stream,longoffset,intorigin);其中,origin可以是SEEK_CUR,SEEK_END或SEEK_SETlongftell(FILE*stream);字符串變量I/O
intsprintf(char*buffer,constchar*format[,argument]...); intsscanf(constchar*buffer, constchar*format[,argument]...);輸入/輸出(I/O)基于類庫的I/O(面向?qū)ο螅┗镜牧黝惣捌洳僮鱅/O類庫提供的輸入/輸出操作是由一些類來實現(xiàn)的,其中istream(輸入流)和ostream(輸出流)是兩個基本的類,由它們派生出其它的類,如:iostream(輸入/輸出流)等,這些類是在頭文件iostream.h中聲明的。I/O流類提供了兩個基本操作:>>(抽取,由istream類提供)和<<(插入,由ostream類提供)用于對基本數(shù)據(jù)類型的數(shù)據(jù)進(jìn)行輸入/輸出。輸入:創(chuàng)建一個istream類(或其派生類)的對象o,
o>>x;//x是一個變量輸出:創(chuàng)建一個ostream類(或其派生類)的對象o,
o<<x;//x是一個表達(dá)式輸入/輸出(I/O)I/O類庫中的主要的類以及它們之間的關(guān)系iosistreamifstreamistrstreamostreamofstreamostrstreamiostreamfstreamstrstream輸入/輸出(I/O)I/O流庫的三類輸入/輸出操作控制臺I/O
從鍵盤輸入/輸出到顯示器或打印機。文件I/O
從文件輸入/輸出到文件。字符串I/O
從字符串變量輸入/輸出到字符串變量。輸入/輸出(I/O)控制臺I/O #include<iostream.h>
在I/O流庫中預(yù)定義了四個流對象,用于進(jìn)行控制臺的I/O。cin:istream類的對象,對應(yīng)鍵盤。cout:ostream類的對象,對應(yīng)顯示器。cerr:ostream類的對象,對應(yīng)顯示器。clog:ostream類的對象,對應(yīng)打印機。輸出
任何基本數(shù)據(jù)類型的數(shù)據(jù)和指針都可以通過cout、cerr、clog對象和操作符<<進(jìn)行輸出。輸入/輸出(I/O)intx;cout<<x;char*p=“abcd”;cout<<p;//輸出字符串“abcd”而不是字符串“abcd”的首地址。cout<<(void*)p;//輸出字符串“abcd”的首地址,即變量p的值。格式化輸出輸出相應(yīng)控制字符,如’\n’表示換行等。輸出操縱符(manipulator)<iomanip.h>
cout<<hex<<x<<endl;利用cout輸出時,也可以用cout的基于字節(jié)流的操作來進(jìn)行,如:cout.put(charch);
cout.write(constchar*str,intlength);輸入/輸出(I/O)輸入
任何基本數(shù)據(jù)類型的數(shù)據(jù)都可以通過cin對象和操作符>>進(jìn)行輸入。
intx;charstr[255];cin>>x>>str;
輸入時也可以通過一些操縱符來控制輸入的行為
cin>>setw(9)>>str;
使用cin的基于字節(jié)流的操作來進(jìn)行輸入
cin.get(char&ch); cin.getline(char*buf,intlength,chardelim=’\n’);輸入/輸出(I/O)操作符<<和>>的重載為了能對自定義類的對象進(jìn)行輸入/輸出,需要對<<和>>進(jìn)行重載。操作符<<和>>只能作為全局(友元)函數(shù)重載。
classCPoint2D {doublex,y; public: … friendostream&operator<<(ostream&,CPoint2D&); }; ostream&operator<<(ostream&out,CPoint2D&a) { out<<a.x<<‘,’<<a.y<<endl; returnout; } … CPoint2Da; cout<<a;輸入/輸出(I/O)如果CPoint3D是CPoint2D的派生類classCPoint3D:publicCPoint2D{ doublez; …}; …...CPoint3Db;cout<<b;//只顯示b.x和b.y,而沒有顯示b.zclassCPoint3D:publicCPoint2D{ doublez; public: friendostream&operator<<(ostream&,CPoint3D&); }; ostream&operator<<(ostream&out,CPoint3D&b) { out<<b.x<<‘,’<<b.y<<‘,’<<b.z<<endl; returnout;}注意:這不是繼承!輸入/輸出(I/O)classCPoint2D {doublex,y; public: … virtualvoiddisplay(ostream&out) {out<<x<<‘,’<<y<<endl;} }; ostream&operator<<(ostream&out,CPoint2D&a) { a.display(out); returnout;}classCPoint3D:publicCPoint2D{doublez;public:…voiddisplay(ostream&out){CPoint2D::display();out<<‘,’<<z<<endl;}}A*p;…cout<<*p;輸入/輸出(I/O)文件I/O
對外部文件進(jìn)行I/O。
#include<iostream.h> #include<fstream.h>
輸出
首先創(chuàng)建一個ofstream類(在I/O流庫中定義的,是ostream類的派生類)的對象。
直接
ofstreamout_file(<文件名>,<打開方式>,<共享方式>);間接
ofstreamout_file;out_file.open(<文件名>,<打開方式>,<共享方式>);輸入/輸出(I/O)<文件名>:對象out_file對應(yīng)的外部文件名<打開方式>:ios::out,ios::app等<共享方式>:filebuf::sh_none,filebuf::sh_read等由于種種原因,打開文件操作可能失敗。因此,打開文件時應(yīng)判斷打開是否成功,只有文件打開成功后才能對文件進(jìn)行操作。
if(!out_file){//失敗}
或if(!out_file.is_open()){//失敗}文件成功打開后,可以使用操作符<<或ofstream類的其它操作進(jìn)行輸出。
輸入/輸出(I/O)out_file<<x<<y<<endl; out_file.put('A'); out_file.write("ABCDEFG",7);
最后,使用close關(guān)閉文件
out_file.close();輸入
首先創(chuàng)建一個ifstream類(在I/O流庫中定義的,是istream類的派生類)的對象。
ifstreamin_file(<文件名>,<打開方式>,<共享方式>);
ifstreamin_file; in_file.open(<文件名>,<打開方式>,<共享方式>);或輸入/輸出(I/O)<文件名>:對象in_file對應(yīng)的外部文件名<打開方式>:ios::in等<共享方式>:filebuf::sh_none,filebuf::sh_read等必須對文件打開是否成功進(jìn)行判斷(同輸出文件)。
再使用操作符>>或ifstream類的其它操作進(jìn)行輸入。
in_file>>x>>y; in_file.get(ch); in_file.getline(buf,length,’\n’); in_file.read(buf,length);
輸入/輸出(I/O)在文件輸入操作過程中,常常需要判斷文件是否已結(jié)束(內(nèi)容被讀完),可以調(diào)用:
in_file.eof()//返回0表示未結(jié)束,非0表示結(jié)束。
最后,使用close關(guān)閉文件:
in_file.close();注意:從文件中讀數(shù)據(jù)時必須知道所讀文件中的數(shù)據(jù)格式!包括數(shù)據(jù)的類型和數(shù)據(jù)的存貯方式。存貯方式有文本方式(text)和二進(jìn)制方式(binary)。輸入/輸出(I/O)文本方式存貯的文件和二進(jìn)制方式存貯的文件的主要區(qū)別文本文件只包含可顯示字符(ASCII編碼為:0x20~0x7F)和若干個控制字符:0x0D(‘\r’)、0x0A(‘\n’)、0x09(‘\t’)以及0x1A(文件結(jié)束符),一般用于存貯不帶格式信息(回車、換行以及制表(橫向跳格)除外)的文本、源程序以及文本數(shù)據(jù)等。二進(jìn)制文件包含任意的二進(jìn)制字節(jié),一般用于存貯帶格式信息文本、目標(biāo)代碼程序以及二進(jìn)制數(shù)據(jù)等。輸入/輸出(I/O)例:對于一個整型數(shù)1234567,可以用兩種方式保存到文件中:1.依次把1,2,3,4,5,6,7的ASCII碼(7個字節(jié))寫入文件(文本文件),文件中包含7個字節(jié)。
inti=1234567;out_file<<i;
2.把1234567的補碼(內(nèi)部表示)0x0012D687(4個字節(jié))寫入文件(二進(jìn)制文件),文件中包含4個字節(jié)。
inti=1234567;out_file.write(&i,4);當(dāng)從上述文件中讀取數(shù)據(jù)時,首先要知道讀取的數(shù)據(jù)種類(整型),其次要知道該數(shù)據(jù)是以什么方式存貯的(text或bibary),否則無法讀入數(shù)據(jù)。
in_file>>j; //正確讀入格式1中的數(shù)據(jù) in_file.read(&j,4);//正確讀入格式2中的數(shù)據(jù)輸入/輸出(I/O)在打開文件時,除了要指定文件的讀寫方式(ios::out,ios::app,ios::in,等)外,還可以指定文件是text還是binary,默認(rèn)的是text。在打開方式中,可以把ios::binary通過運算符'|'(按位或)與ios::out、ios::app或ios::in結(jié)合,指定二進(jìn)制文件。如:
ios::in|ios::binary
//打開一個二進(jìn)制文件讀ios::out|ios::binary //打開一個二進(jìn)制文件寫如果以text方式打開文件(讀或?qū)懀?,在讀操作中,遇見連續(xù)的0x0D和0x0A兩個字符時,系統(tǒng)會把它們轉(zhuǎn)換成一個字符0x0A('\n')讀入;在寫操作中,輸出字符0x0A('\n')時,系統(tǒng)把它轉(zhuǎn)換成兩個字符0x0D和0x0A寫入文件。另外,在讀操作中遇見字符0x1A,系統(tǒng)認(rèn)為是文件結(jié)束。因此,以文本方式打開一個二進(jìn)制文件讀會造成數(shù)據(jù)的丟失。輸入/輸出(I/O)輸入/輸出
如果打開一個文件,既能讀入,也能輸出,則需要創(chuàng)建一個fstream類的對象,fstream類是從iostream類派生的。
fstreamfile("d:\\test.txt",ios::in|ios::out);隨機存取文件
默認(rèn)情況下,I/O流庫中的類所提供的輸入/輸出操作是順序進(jìn)行的,即,在讀入時,要讀文件中的第n個數(shù)據(jù),必須先把前n-1個數(shù)據(jù)讀入;在寫出時,要寫文件中的第n個數(shù)據(jù),必須先把前n-1個數(shù)據(jù)寫出。每個文件都有一個內(nèi)部文件位置指針,讀/寫時,每讀/寫一個字節(jié),這個指針會自動往后走一個字節(jié)位置。輸入/輸出(I/O)為了能夠隨機讀寫文件,必須顯示地指出讀寫的位置。讀寫位置可通過設(shè)置文件內(nèi)部指針來指定。輸入文件
istream&istream::seekg(<位置>);
istream&istream::seekg(<偏移量>,<參照位置>);
streamposistream::tellg();輸出文件
ostream&ostream::seekp(<位置>);
ostream&ostream::seekp(<偏移量>,<參照位置>);
streamposostream::tellp();<參照位置>:ios::beg,ios::cur,ios::end重載同控制臺I/O。輸入/輸出(I/O)字符串I/O
用于從字符串變量輸入和向字符串變量輸出。 #include<iostream.h> #include<strstrea.h>輸出首先創(chuàng)建一個ostrstream類(在I/O流庫中定義的,是ostream類的派生類)的對象。
ostrstreamstr_buf; ostrstreamstr_buf(char*p,intlength,<方式>);其中,p為一個緩沖指針,length為緩沖大小<方式>:ios::out,ios::app等。如果str_buf采用默認(rèn)構(gòu)造,則采用可動態(tài)擴充的內(nèi)部緩沖。或輸入/輸出(I/O)使用操作符<<或ostrstream類的其它操作進(jìn)行輸出
str_buf<<x<<y<<endl;使用str操作獲取str_buf中字符串緩沖頭指針:
char*p=str_buf.str();輸入首先創(chuàng)建一個istrstream類(在I/O流庫中定義的,是istream類的派生類)的對象。
istrstreamstr_buf(char*p); istrstreamstr_buf(char*p,intlength);
p為一個緩沖指針,length為緩沖大小,如果str_buf的構(gòu)造沒有給出length,則認(rèn)為p以‘\0’結(jié)束?;蜉斎?輸出(I/O)使用操作符>>或istrstream類的其它操作進(jìn)行輸入
str_buf>>x>>y;可以使用str操作獲取str_buf中字符串緩沖頭指針:
char*p=str_buf.str();重載
同控制臺I/O。異常處理異常的概念 Exception程序的錯誤:語法錯誤,邏輯錯誤、運行異常語法錯誤是指程序的書寫不符合語言的語法規(guī)則,由編譯程序發(fā)現(xiàn)。邏輯錯誤或語義錯誤是指程序設(shè)計不當(dāng)造成程序沒有完成預(yù)期的功能,通過測試發(fā)現(xiàn)。運行異常是指由程序運行環(huán)境造成的程序異常終止,如:內(nèi)存空間不足、打開不存在的文件、程序執(zhí)行了除以0的指令,等等。異常處理在程序運行環(huán)境正常的情況下,導(dǎo)致運行異常的錯誤是不會出現(xiàn)的,這類錯誤是可以預(yù)料的,但是無法避免。為了保證程序的魯棒性(Robustness),必須在程序中對它們進(jìn)行預(yù)見性處理。 voidf(char*str) {ifstreamfile(str); if(file.fail()) {…//異常處理 }
intx; file>>x; … }
上述的異常處理是在發(fā)現(xiàn)錯誤的地方(函數(shù))就地處理,有時就地處理往往不合適,而需要由調(diào)用的函數(shù)來處理。例如:在上述的函數(shù)f中用到的文件名str,可能是在調(diào)用f的函數(shù)中,通過某種方式(如:用戶輸入)得到的,當(dāng)函數(shù)f發(fā)現(xiàn)文件不存在,應(yīng)該讓調(diào)用者重新獲得文件名,然后重新調(diào)用f,即,發(fā)現(xiàn)異常的函數(shù)和處理異常的函數(shù)可以不是同一個函數(shù)。異常處理語言中如果沒有一種專門的異常處理機制,要想實現(xiàn)上述的異常處理思想有時是比較麻煩的,并且,也會使得程序結(jié)構(gòu)非常不清楚。例如:被調(diào)函數(shù)通過返回不同的值來告訴調(diào)用函數(shù)有關(guān)被調(diào)函數(shù)的執(zhí)行情況(正常、異常);調(diào)用函數(shù)根據(jù)被調(diào)函數(shù)的返回值作出不同的處理(繼續(xù)執(zhí)行、處理異常或返回到調(diào)用函數(shù)的調(diào)用函數(shù)進(jìn)行異常處理)。上述做法,首先,會使得程序?qū)φ?zhí)行過程的描述顯得十分不清楚。其次,對一個原來沒有返回值的被調(diào)函數(shù),為了反映調(diào)用是否正常,往往要把它定義成有返回值,用于返回它的執(zhí)行情況。另外,對一個正常執(zhí)行后必須返回一個值的被調(diào)函數(shù),調(diào)用函數(shù)往往無法根據(jù)被調(diào)函數(shù)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 高考全國卷思想政治考試卷題庫(含答案解析)
- 南昌市2024江西南昌市市級機關(guān)事業(yè)單位資產(chǎn)管理服務(wù)中心招聘2人筆試歷年參考題庫典型考點附帶答案詳解(3卷合一)
- 網(wǎng)頁設(shè)計面試題及答案解析
- 教育專家招聘面試高效提問與答案解析
- 游戲開發(fā)崗位面試問題解析
- 橡膠廠長面試題及答案
- 2025年私家車共享服務(wù)平臺建設(shè)可行性研究報告
- 2025年城市水資源管理系統(tǒng)創(chuàng)新項目可行性研究報告
- 2025年智能化倉儲管理系統(tǒng)開發(fā)可行性研究報告
- 2025年全鏈條食品追溯系統(tǒng)項目可行性研究報告
- 教學(xué)查房課件-強直性脊柱炎
- 傳染病報告卡
- 句法成分課件(共18張)統(tǒng)編版語文八年級上冊
- 2023版中國近現(xiàn)代史綱要課件:07第七專題 星星之火可以燎原
- 通知書產(chǎn)品升級通知怎么寫
- 氣管插管術(shù) 氣管插管術(shù)
- 大學(xué)《實驗診斷學(xué)》實驗八:病例分析培訓(xùn)課件
- GB/T 28400-2012釹鎂合金
- 多維閱讀第8級Moon Mouse 明星老鼠的秘密
- 骨髓增生異常綜合癥課件整理
- 心肌梗死院前急救課件
評論
0/150
提交評論