面向?qū)ο蟪绦蛟O(shè)計(jì)之多態(tài)性與虛函數(shù)_第1頁
面向?qū)ο蟪绦蛟O(shè)計(jì)之多態(tài)性與虛函數(shù)_第2頁
面向?qū)ο蟪绦蛟O(shè)計(jì)之多態(tài)性與虛函數(shù)_第3頁
面向?qū)ο蟪绦蛟O(shè)計(jì)之多態(tài)性與虛函數(shù)_第4頁
面向?qū)ο蟪绦蛟O(shè)計(jì)之多態(tài)性與虛函數(shù)_第5頁
已閱讀5頁,還剩58頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

面向?qū)ο蟪绦蛟O(shè)計(jì)之多態(tài)性與虛函數(shù)6.1多態(tài)性的概念 多態(tài)性(polymorphism)是面向?qū)ο蟪绦蛟O(shè)計(jì)的重要特征。一個(gè)算法語言如果只支持類,而不支持多態(tài),只能說是基于對(duì)象的語言,如Ada,VB。C++支持多態(tài)性,在C++程序設(shè)計(jì)中能夠?qū)崿F(xiàn)多態(tài)性。利用多態(tài)性,可以設(shè)計(jì)和擴(kuò)展一個(gè)易于擴(kuò)展的系統(tǒng)。什么叫多態(tài)?多態(tài)的意思是一種事物的多種形態(tài)。在C++中,是指具有不同功能的函數(shù)可以用同一個(gè)函數(shù)名。面向?qū)ο蠓椒ㄖ幸话闶沁@樣描述多態(tài)性的:向不同的對(duì)象發(fā)送同一個(gè)消息,不同的對(duì)象在接收時(shí)會(huì)產(chǎn)生不同的行為(即方法)。 第2頁,共63頁,2024年2月25日,星期天寫出程序運(yùn)行結(jié)果#include<iostream>#include<string>Usingnamespacestd;classstudent{public:student(intn,stringnam,floats){num=n;name=nam;score=s;}voiddisplay(){cout<<“num:”<<num<<“name:”<<name<<“score:”<<score<<endl;}protected:intnum;stringname;floatscore;};classgraduate:publicstudent{public:graduate(intn,stringnam,floats,floatp):student(n,nam,s),pay(p){}voiddisplay(){cout<<“num:”<<num<<“name:”<<name<<“score:”<<score<<“pay:”<<pay<<endl;}private:floatpay;};voidmain(){students1(1001,”Li”,98.5);graduateg1(2001,”Liu”,90.5,800.5);student*pt=&s1;pt->display();pt=&g1;pt->display();}

第3頁,共63頁,2024年2月25日,星期天6.1多態(tài)性的概念 我們其實(shí)已經(jīng)接觸過多態(tài)性的現(xiàn)象。如函數(shù)的重載多態(tài)性分類:從系統(tǒng)實(shí)現(xiàn)的角度看,多態(tài)性分為以下兩類:靜態(tài)多態(tài)性:又稱編譯時(shí)的多態(tài)性。如函數(shù)重載屬于靜態(tài)多態(tài)性。動(dòng)態(tài)多態(tài)性:有稱為運(yùn)行時(shí)的多態(tài)性。它主要表現(xiàn)為虛函數(shù)(virtualfunction)。第4頁,共63頁,2024年2月25日,星期天6.3虛函數(shù)

能否用一個(gè)調(diào)用形式,既能調(diào)用派生類的函數(shù),又能調(diào)用基類同名函數(shù)?C++中的虛函數(shù)就是用來解決這一問題。虛函數(shù)的作用:虛函數(shù)的作用是允許在派生類中重新定義與基類同名的函數(shù),并且可以通過基類指針或引用來訪問基類和派生類中的同名函數(shù)。第5頁,共63頁,2024年2月25日,星期天6.3虛函數(shù)#include<iostream.h>#include<string.h>classstudent{public:student(intn,stringnam,floats){num=n;name=nam;score=s;}voiddisplay(){cout<<“num:”<<num<<“name:”<<name<<“score:”<<score<<endl;}protected:intnum;stringname;floatscore;};classgraduate:publicstudent{public:graduate(intn,stringnam,floats,floatp):student(n,nam,s),pay(p){}voiddisplay(){cout<<“num:”<<num<<“name:”<<name<<“score:”<<score<<“pay:”<<pay<<endl;}private:floatpay;};voidmain(){students1(1001,”Li”,98.5);graduateg1(2001,”Liu”,90.5,800.5);student*pt=&s1;pt->display();//指向基類對(duì)象s1pt=&g1;pt->display();//指向派生類對(duì)象g1,僅輸出了派生類的基類數(shù)據(jù)成員,因?yàn)樗{(diào)用的是基類成員函數(shù)display!}假如想輸出派生類的全部數(shù)據(jù),當(dāng)然可以采用下面兩種方法之一:通過派生類對(duì)象名g1,調(diào)用派生類對(duì)象的成員函數(shù):g1.display();定義一個(gè)指向派生類的指針ptr,并指向g1,然后用ptr->display()。第6頁,共63頁,2024年2月25日,星期天6.3虛函數(shù) 我們可以用虛函數(shù)可以順利解決這一問題。方法是:在基類student中聲明display函數(shù)時(shí),在最左邊加上一個(gè)關(guān)鍵字virtual:

virtualvoiddisplay();

就可以student類的display函數(shù)聲明為虛函數(shù),程序其它部分不變編譯運(yùn)行后,可見,使用pt->display(),的確將graduate類對(duì)象g1的全部數(shù)據(jù)顯示了出來,說明它調(diào)用的是g1的成員函數(shù)display。在派生類中重新定義該函數(shù),要求函數(shù)名、函數(shù)類型、參數(shù)表完全相同。但不加virtual關(guān)鍵字。只在類里的成員函數(shù)聲明時(shí),加上關(guān)鍵字virtual,在類外定義定義虛函數(shù)時(shí),不加virtual關(guān)鍵字。定義一個(gè)指向基類對(duì)象的指針,并使她指向同一類中的某一對(duì)象;通過該指針標(biāo)量調(diào)用此虛函數(shù),此時(shí)調(diào)用的就是指針變量指向的對(duì)象的同名函數(shù),而不是基類的同名函數(shù)!第7頁,共63頁,2024年2月25日,星期天6.3虛函數(shù) 通過使用虛函數(shù)和指針,就能方便地調(diào)用同一類族中不同類對(duì)象的同名函數(shù),只要先用基類指針指向該對(duì)象即可。#include<iostream.h>#include<string.h>classstudent{public:student(intn,stringnam,floats){num=n;name=nam;score=s;}

virtualvoiddisplay(){cout<<“num:”<<num<<“name:”<<name<<“score:”<<score<<endl;}protected:intnum;stringname;floatscore;};classgraduate:publicstudent{public:graduate(intn,stringnam,floats,floatp):student(n,nam,s),pay(p){}voiddisplay(){cout<<“num:”<<num<<“name:”<<name<<“score:”<<score<<“pay:”<<pay<<endl;}private:floatpay;};voidmain(){students1(1001,”Li”,98.5);graduateg1(2001,”Liu”,90.5,800.5);student*pt=&s1;pt->display();//指向基類對(duì)象s1pt=&g1;pt->display();//指向派生類對(duì)象g1,調(diào)用g1的顯示函數(shù)display,打印出g1全部數(shù)據(jù)成員}第8頁,共63頁,2024年2月25日,星期天6.3虛函數(shù) 將函數(shù)重載與虛函數(shù)比較,可見:函數(shù)重載是解決的是同一層次上的同名函數(shù)的問題。是橫向重載。虛函數(shù)解決的是不同派生層次上的同名函數(shù)的問題。相當(dāng)于縱向重載。同一類族的虛函數(shù)的首部是相同的;而重載函數(shù)的首部不相同(參數(shù)表不能相同)。第9頁,共63頁,2024年2月25日,星期天6.3虛函數(shù)靜態(tài)關(guān)聯(lián)與動(dòng)態(tài)關(guān)聯(lián)

C++在編譯或運(yùn)行時(shí),對(duì)多個(gè)同名函數(shù)究竟調(diào)用哪一個(gè)函數(shù),需要一定的機(jī)制來確定。這種確定調(diào)用的具體對(duì)象的過程稱為“關(guān)聯(lián)(binding)”,即把函數(shù)名與某一個(gè)類對(duì)象捆綁在一起。 函數(shù)重載,在編譯時(shí)就可確定其調(diào)用的函數(shù)是哪一個(gè);通過對(duì)象名調(diào)用虛函數(shù),在編譯時(shí)也可確定其調(diào)用的虛函數(shù)屬于哪一個(gè)類。其過程稱為“靜態(tài)關(guān)聯(lián)(staticbinding),因?yàn)槭窃谶\(yùn)行前進(jìn)行關(guān)聯(lián)的,又成為早期關(guān)聯(lián)(earlybinding)。第10頁,共63頁,2024年2月25日,星期天6.3虛函數(shù) 通過指針和虛函數(shù)的結(jié)合,在編譯階段是沒法進(jìn)行關(guān)聯(lián)的,因?yàn)榫幾g只作靜態(tài)的語法檢查,光從語句形式pt->display()無法確定調(diào)用的對(duì)象,也就沒法關(guān)聯(lián)。 出現(xiàn)這種情況,我們可以在運(yùn)行階段來處理關(guān)聯(lián)。在運(yùn)行階段,基類指針先指向某一個(gè)對(duì)象,然后通過指針調(diào)用該對(duì)象的成員函數(shù)。此時(shí)調(diào)用哪個(gè)函數(shù)是確定的,沒有不確定因素。例如語句pt=&g1;pt->display();非常確定的是調(diào)用g1對(duì)象的成員函數(shù)display。 這種情況由于是在運(yùn)行階段將虛函數(shù)與某一類對(duì)象“綁定”在一起的,因此稱為“動(dòng)態(tài)關(guān)聯(lián)(dynamicbinding),或“滯后關(guān)聯(lián)(latebinding)”。第11頁,共63頁,2024年2月25日,星期天6.3虛函數(shù)使用虛函數(shù),要注意只能用virtual聲明類的成員函數(shù),類外的普通函數(shù)不能聲明成虛函數(shù),因?yàn)樗鼪]有繼承的操作。一個(gè)成員函數(shù)被聲明成虛函數(shù)后,在同一類族中的類就不能再定義一個(gè)非virtual的、但與該函數(shù)具有相同參數(shù)表和返回類型的同名函數(shù)。使用虛函數(shù),系統(tǒng)要有一定的空間開銷。當(dāng)一個(gè)類帶有虛函數(shù)時(shí),編譯系統(tǒng)會(huì)為該類構(gòu)造一個(gè)虛函數(shù)表(virtualfunctiontable,vtable),它是一個(gè)指針數(shù)組,存放每個(gè)虛函數(shù)的入口地址。 系統(tǒng)在進(jìn)行動(dòng)態(tài)關(guān)聯(lián)時(shí)的時(shí)間開銷是很少的,所以多態(tài)性運(yùn)行效率非常高。第12頁,共63頁,2024年2月25日,星期天6.3虛函數(shù)什么情況下使用虛函數(shù)?成員函數(shù)所在的類是否會(huì)作為基類?成員函數(shù)被繼承后有沒有可能發(fā)生功能變化,如果兩個(gè)因素都具備,就應(yīng)該將它聲明成虛函數(shù)。如果成員函數(shù)被繼承后功能不變,或派生類用不到該函數(shù),就不要聲明成虛函數(shù)。應(yīng)考慮對(duì)成員函數(shù)的訪問是通過對(duì)象名還是基類指針,如果是通過基類指針或引用訪問,則應(yīng)當(dāng)聲明為虛函數(shù)。有時(shí)基類中定義虛函數(shù)時(shí)并不定義它的函數(shù)體,即函數(shù)體為空。其作用只是定義了一個(gè)虛函數(shù)名,具體功能留給派生類添加(6.4節(jié)會(huì)討論這種情況)。第13頁,共63頁,2024年2月25日,星期天6.3虛函數(shù)虛析構(gòu)函數(shù)問題的引出:我們知道,當(dāng)派生類對(duì)象撤消時(shí),系統(tǒng)先調(diào)用派生類析構(gòu)函數(shù),再調(diào)用基類析構(gòu)函數(shù)。但是,如果用new運(yùn)算符建立了一個(gè)派生類臨時(shí)對(duì)象,但用一個(gè)基類指針指向它,當(dāng)程序用帶指針參數(shù)的delete撤消對(duì)象時(shí),會(huì)發(fā)生讓人不能接受的情況:系統(tǒng)只析構(gòu)基類對(duì)象,而不析構(gòu)派生類對(duì)象:classpoint{public:point(){}~point(){cout<<“析構(gòu)基類對(duì)象”<<endl;}};classcircle:publicpoint{public:circle(){}~circle(){cout<<“析構(gòu)派生類對(duì)象”<<endl;}private:intradius;};intmain(){point*p=newcircle;

//指針為指向基類對(duì)象指針,

//但實(shí)際指向臨時(shí)派生類對(duì)象deletep;return0;}第14頁,共63頁,2024年2月25日,星期天6.3虛函數(shù) 實(shí)際上,程序只析構(gòu)了基類對(duì)象,而沒有析構(gòu)派生類對(duì)象,為什么呢?因?yàn)橹羔榩為基類指針,系統(tǒng)認(rèn)為它只有基類對(duì)象,而與派生類對(duì)象無關(guān)。實(shí)際上,由于該指針被指向了一個(gè)臨時(shí)派生類對(duì)象,所以還應(yīng)該這個(gè)臨時(shí)的析構(gòu)派生類對(duì)象。解決的辦法:可以將基類的析構(gòu)函數(shù)聲明為虛析構(gòu)函數(shù)。如:

virtual~point(){cout<<“析構(gòu)基類對(duì)象”<<endl;}

程序其它部分不動(dòng),就行了。 當(dāng)基類的析構(gòu)函數(shù)被定義成virtual,無論指針指向同一類族中的哪一個(gè)對(duì)象,當(dāng)撤消對(duì)象時(shí),系統(tǒng)會(huì)采用動(dòng)態(tài)關(guān)聯(lián),調(diào)用相應(yīng)的析構(gòu)函數(shù),清理該對(duì)象,然后再析構(gòu)基類對(duì)象。第15頁,共63頁,2024年2月25日,星期天6.4純虛函數(shù)與抽象類 前面已經(jīng)提到,有時(shí)在基類中將某一成員函數(shù)定為虛函數(shù)并不是基類本身的需要,而是派生類的需要。在基類中預(yù)留一個(gè)函數(shù)名,具體功能留給派生類根據(jù)需要去定義。 在上一節(jié)中基類point中有定義面積area函數(shù),是因?yàn)椤包c(diǎn)”沒有面積的概念。但是,其直接派生類circle和間接派生類cylinder卻都需要area函數(shù),而且這兩個(gè)area函數(shù)的功能還不相同,一個(gè)是求圓面積,一個(gè)是求圓柱體表面積。 也許會(huì)想到,在基類point中加一個(gè)area函數(shù),并聲明為虛函數(shù):

virtualfloatarea()const{return0;}

其返回0表示“點(diǎn)”沒有面積。其實(shí),在基類中并不使用這個(gè)函數(shù),其返回值也沒有意義。第16頁,共63頁,2024年2月25日,星期天6.4純虛函數(shù)與抽象類 為簡化起見,可以不寫出這種無意義的函數(shù)體,只給出函數(shù)的原型,并在后面加上“=0”,如:

virtualfloatarea()const=0;//純虛函數(shù) 這就將area聲明為一個(gè)純虛函數(shù)(purevirtualfunction)純虛函數(shù)的聲明形式

virtual函數(shù)類型函數(shù)名(參數(shù)表)=0; 說明純虛函數(shù)沒有函數(shù)體;最后的“=0”不表示函數(shù)值返回0,它只是形式上的作用,告訴編譯系統(tǒng):這是純虛函數(shù),這是一個(gè)聲明語句,以分號(hào)結(jié)尾。如果基類中聲明了純虛函數(shù),但派生類中定義該函數(shù),則該虛函數(shù)在派生類中仍為純虛函數(shù)。第17頁,共63頁,2024年2月25日,星期天6.4純虛函數(shù)與抽象類純虛函數(shù)的作用 是在基類中為其派生類保留一個(gè)函數(shù)的名字,以便派生類根據(jù)需要對(duì)它進(jìn)行定義。如果基類中沒有保留函數(shù)名,則無法實(shí)現(xiàn)多態(tài)性。第18頁,共63頁,2024年2月25日,星期天6.4純虛函數(shù)與抽象類抽象類什么叫抽象類?一般聲明了一個(gè)類,用來定義若干對(duì)象。但有些類并不是用來生成對(duì)象,而是作為基類去建立派生類。這種不用來定義對(duì)象,而只作為一種基本類型用做繼承的類,就叫抽象類(abstractclass)。由于抽象類常作為基類,我們也稱為抽象基類(abstractbaseclass)。 比如,凡是包含純虛函數(shù)的類都叫抽象類。因?yàn)榧兲摵瘮?shù)不能被調(diào)用,包含純虛函數(shù)的類無法建立對(duì)象。抽象類的作用:是作為一個(gè)類族的共同基類。即,為一個(gè)類族提供一個(gè)公共接口。 一個(gè)類層次結(jié)構(gòu)中可以不包含任何抽象類,每一層次的類都可以建立對(duì)象。但是,許多系統(tǒng)的頂層是一個(gè)抽象類,甚至頂部有好幾層都是抽象類。第19頁,共63頁,2024年2月25日,星期天6.4純虛函數(shù)與抽象類 如果由抽象類所派生出的新類中對(duì)基類的所有純虛函數(shù)都進(jìn)行了定義,這個(gè)派生類就不是抽象類,可以被調(diào)用,成為可以用來定義對(duì)象的具體類(concreteclass)。 如果由抽象類所派生出的新類中對(duì)基類的所有純虛函數(shù)都沒有進(jìn)行定義,這個(gè)派生類就仍然是抽象類。 雖然抽象類不能定義對(duì)象,但可以定義指向抽象類的數(shù)據(jù)的指針。當(dāng)派生類成為具體類之后,就可以用這種指針向派生類對(duì)象,然后通過該指針調(diào)用虛函數(shù),實(shí)現(xiàn)多態(tài)性操作。

第20頁,共63頁,2024年2月25日,星期天編程練習(xí):

定義虛函數(shù),基類為SHAPE,派生出圓形、矩形、三角形類。第21頁,共63頁,2024年2月25日,星期天#include<iostream>usingnamespacestd;//定義抽象基類ShapeclassShape{public://定義純虛函數(shù)};//定義Circle類classCircle:publicShape{public:Circle(doubler):radius(r){}//定義虛函數(shù)

protected:doubleradius;//半徑};//定義Rectangle類classRectangle:publicShape{public:Rectangle(doublew,doubleh):width(w),height(h){}//定義虛函數(shù)

protected:doublewidth,height;};classTriangle:publicShape{public:Triangle(doublew,doubleh):width(w),height(h){}//定義虛函數(shù)

protected:doublewidth,height;};第22頁,共63頁,2024年2月25日,星期天#include<iostream>usingnamespacestd;//定義抽象基類ShapeclassShape{public:virtualdoublearea()const=0;//純虛函數(shù)};//定義Circle類classCircle:publicShape{public:Circle(doubler):radius(r){}

virtualdoublearea()const{return3.14159*radius*radius;};//定義虛函數(shù)

protected:doubleradius;//半徑};//定義Rectangle類classRectangle:publicShape{public:Rectangle(doublew,doubleh):width(w),height(h){}

virtualdoublearea()const{returnwidth*height;}//定義虛函數(shù)

protected:doublewidth,height;};classTriangle:publicShape{public:Triangle(doublew,doubleh):width(w),height(h){}

virtualdoublearea()const{return0.5*width*height;}//定義虛函數(shù)

protected:doublewidth,height;};第23頁,共63頁,2024年2月25日,星期天續(xù):定義一個(gè)函數(shù)printArea,以對(duì)象為形參,輸出三種形狀的面積

intmain(){Circlecircle(12.6);//建立Circle類對(duì)象circlecout<<"areaofcircle=";printArea(circle);//輸出circle的面積

Rectanglerectangle(4.5,8.4);//建立Rectangle類對(duì)象rectanglecout<<"areaofrectangle=";printArea(rectangle);//輸出rectangle的面積

Triangletriangle(4.5,8.4);//建立Triangle類對(duì)象

cout<<"areaoftriangle=";printArea(triangle);//輸出triangle的面積

return0;}第24頁,共63頁,2024年2月25日,星期天//輸出面積的函數(shù)voidprintArea(constShape&s){cout<<s.area()<<endl;}第25頁,共63頁,2024年2月25日,星期天6.4純虛函數(shù)與抽象類 多態(tài)性把操作細(xì)節(jié)留給類的設(shè)計(jì)者(專業(yè)人員)去完成,而讓編程人員(類的使用者)只需做一些宏觀性的工作,告訴系統(tǒng)做什么,不必考慮怎么做,簡化了應(yīng)用程序的編碼工作。 因此有人說,多態(tài)性是開啟繼承功能的鑰匙。第26頁,共63頁,2024年2月25日,星期天Object-Oriented

Programming

inC++

第七章輸入輸出流第27頁,共63頁,2024年2月25日,星期天第一章C++的初步知識(shí)第二章類和對(duì)象第三章再論類和對(duì)象第四章運(yùn)算符重載第五章繼承與派生第六章多態(tài)性與虛函數(shù)第七章輸入輸出流第八章C++工具第28頁,共63頁,2024年2月25日,星期天7.1C++的輸入與輸出7.2標(biāo)準(zhǔn)輸出流7.3標(biāo)準(zhǔn)出入流7.4文件操作與文件流7.5字符串流第29頁,共63頁,2024年2月25日,星期天7.1C++的輸入和輸出輸入輸出的含義:從操作系統(tǒng)角度看,每一個(gè)與主機(jī)相連的輸入輸出設(shè)備都被看做一個(gè)文件。終端鍵盤是輸入文件,終端顯示器是輸出文件。磁盤或光盤也可以被看作是輸入輸出文件。程序的輸入:指的是從輸入文件將數(shù)據(jù)傳送給程序;程序的輸出:指的是從程序?qū)?shù)據(jù)輸出給輸出文件。C++的輸入輸出包括以下三個(gè)方面的內(nèi)容:標(biāo)準(zhǔn)設(shè)備輸入輸出,從鍵盤輸入。輸出到顯示器。簡稱標(biāo)準(zhǔn)I/O。以外存儲(chǔ)器文件為對(duì)象的輸入輸出。指從磁盤文件中輸入數(shù)據(jù),將數(shù)據(jù)輸出到磁盤文件中。簡稱文件I/O對(duì)內(nèi)存中指定的空間進(jìn)行輸入輸出。通常指定一個(gè)字符數(shù)組作為存儲(chǔ)空間,它稱為字符串輸入輸出,簡稱串I/O C++采取了不同的方法,實(shí)現(xiàn)這三種輸入輸出。第30頁,共63頁,2024年2月25日,星期天7.1C++的輸入和輸出C++輸入輸出流

C++的輸入輸出流是指由若干字節(jié)組成的字節(jié)序列。在內(nèi)存中,系統(tǒng)為每一個(gè)數(shù)據(jù)流開辟一個(gè)緩沖區(qū),用來存放流中的數(shù)據(jù)。當(dāng)使用cout和插入符“<<”輸出數(shù)據(jù)時(shí),先將這些數(shù)據(jù)送到程序中的輸出緩沖區(qū)保存,直到緩沖區(qū)滿了或遇到endl,就將緩沖區(qū)中的全部數(shù)據(jù)送到顯示器。在輸入時(shí),從鍵盤輸入的數(shù)據(jù)先放在鍵盤緩沖區(qū)中,形成cin流,然后用提取運(yùn)算符“>>”從輸入緩沖區(qū)提取數(shù)據(jù),送給程序中的相關(guān)變量。 總之,內(nèi)存緩沖區(qū)中的數(shù)據(jù)就是流。第31頁,共63頁,2024年2月25日,星期天7.1C++的輸入和輸出流類與流對(duì)象:在C++中,輸入輸出流被定義成類,C++的I/O庫中的類稱為流類(streamclass)。用流類定義的對(duì)象稱為流對(duì)象。

cout和cin并不是C++提供的語句,它們是iostream類的對(duì)象。正如C++沒有提供賦值語句,只提供了賦值表達(dá)式(表達(dá)式后面加分號(hào),形成語句)。 在iostream頭文件中重載運(yùn)算符:“<<”和“>>”在C++中是位移運(yùn)算符,由于在iostream頭文件中對(duì)它們進(jìn)行了重載,使它們能用做標(biāo)準(zhǔn)輸入輸出運(yùn)算符,所以,在用它們的程序中必須使用#include<iostream>語句把iostream類包含到程序中。 下面我們來看看I/O類庫中類的情況。第32頁,共63頁,2024年2月25日,星期天7.1C++的輸入和輸出I/O類庫中常用的流類

strstreamstrstreamstrstream輸入字符串流類輸出字符串流類輸入輸出字符串流類istrstreamostrstreamstrstreamfstreamfstreamfstream輸入文件流類輸出文件流類輸入輸出文件流類ifstreamofstreamfstreamiostreamiostreamiostream通用輸入流和其他輸入流的基類通用輸出流和其他輸出流的基類通用輸入輸出流和其他輸入輸出流的基類istreamostreamiostreamIostream抽象基類ios在哪個(gè)頭文件中聲明作用類名第33頁,共63頁,2024年2月25日,星期天7.1C++的輸入和輸出iostream文件中定義的4種流對(duì)象stderrostream_withassign屏幕標(biāo)準(zhǔn)錯(cuò)誤流clogstderrostream_withassign屏幕標(biāo)準(zhǔn)錯(cuò)誤流cerrstdoutostream_withassign屏幕標(biāo)準(zhǔn)輸出流coutstdinistream_withassign鍵盤標(biāo)準(zhǔn)輸入流cinC語言對(duì)應(yīng)文件對(duì)應(yīng)的類對(duì)應(yīng)設(shè)備含義對(duì)象說明

cin是istream的派生類istream_withassign的對(duì)象,它是從鍵盤輸入數(shù)據(jù)流到內(nèi)存;

cout是ostream的派生類ostream_withassign的對(duì)象,它從內(nèi)存輸出數(shù)據(jù)流到顯示器;

cerr和clog相似,均為向顯示器輸出出錯(cuò)信息第34頁,共63頁,2024年2月25日,星期天7.2標(biāo)準(zhǔn)輸出流clog流對(duì)象:也是標(biāo)準(zhǔn)出錯(cuò)流,是consolelog的縮寫。作用和cerr相同。區(qū)別在于,cerr不經(jīng)過緩沖區(qū),直接向顯示器輸出,而clog經(jīng)過緩沖區(qū),緩沖區(qū)裝滿后或遇到endl時(shí),向顯示器輸出。#include<iostream.h>#include<math.h>voidmain(){floata,b,c,disc;cout<<"pleaseinputa,b,c:";cin>>a>>b>>c;if(a==0)

cerr<<"aisequaltozero,error!"<<endl;elseif((disc=b*b-4*a*c)<0)

cerr<<"disc=b*b-4*a*c<0"<<endl;else{cout<<"x1="<<(-b+sqrt(disc))/(2*a)<<endl;cout<<"x2="<<(-b-sqrt(disc))/(2*a)<<endl;}}第35頁,共63頁,2024年2月25日,星期天7.2標(biāo)準(zhǔn)輸出流格式輸出:輸出數(shù)據(jù)時(shí),為簡便起見往往不指定輸出格式。但也可以指定輸出格式。 輸出格式有兩種方法:①使用控制符輸出格式;②使用流對(duì)象的有關(guān)成員函數(shù)。使用控制符輸出格式:這些控制符是在頭文件iomanip中定義。程序必須包含該頭文件??刂品饔胐ec,hex,oct分別設(shè)置整數(shù)的基數(shù)為10、16、8setbase(n)設(shè)置整數(shù)基數(shù)為n(n為10,16,8三者之一)setfill(c)設(shè)置填充字符c,c是字符常量或變量setprecision(n)設(shè)置實(shí)數(shù)精度為n位setw(n)設(shè)置字段寬度為nsetiosflags(ios::left/right)輸出數(shù)據(jù)左/右對(duì)齊resetioflags()終止已設(shè)置的輸出格式,在括號(hào)中指定內(nèi)容第36頁,共63頁,2024年2月25日,星期天7.2標(biāo)準(zhǔn)輸出流#include<iostream.h>#include<iomanip.h>intmain(){inta=123;char*pt=“China”;doublepi=22.0/7.0;cout<<“dec:”<<dec<<a<<endl;cout<<“hec:”<<hex<<a<<endl;cout<<“oct:”<<oct<<a<<endl;

cout<<setw(10)<<pt<<endl;cout<<setfill(‘*’)<<setw(10)<<pt<<endl;cout<<“pi=”<<pi<<endl;cout<<“pi=“<<setprecision(4)<<pi<<endl;cout<<“pi=“<<setiosflags(ios::fixed)<<pi<<endl;return0;}第37頁,共63頁,2024年2月25日,星期天7.2標(biāo)準(zhǔn)輸出流用流成員函數(shù)put輸出字符 我們已經(jīng)知道,程序中一般用cout<<實(shí)現(xiàn)輸出,cout流在內(nèi)存中有相應(yīng)的緩沖區(qū)。 有時(shí),我們想只輸出一個(gè)字符,ostream類提供了put成員函數(shù)來滿足這一特殊需求:#include<iostream.h>intmain(){char*a="BASIC";for(inti=4;i>=0;i--)cout.put(*(a+i));cout.put('\n');return0;}第38頁,共63頁,2024年2月25日,星期天7.3標(biāo)準(zhǔn)輸入流cin流:cin流是istream類的對(duì)象。它從標(biāo)準(zhǔn)輸入設(shè)備(鍵盤)獲取數(shù)據(jù),程序中的變量通過流提取符“>>”從流中提取數(shù)據(jù)。用于字符輸入的流成員函數(shù):用get函數(shù)讀入一個(gè)字符:get函數(shù)有三中形式:無參數(shù)、有一個(gè)參數(shù)和3個(gè)參數(shù)的形式。不帶參數(shù)的get函數(shù):其調(diào)用形式為:cin.get()#include<iostream.h>intmain(){charc;cout<<“inputasentence,please:"<<endl;while((c=cin.get())!=EOF)cout<<c;return0;}第39頁,共63頁,2024年2月25日,星期天7.3標(biāo)準(zhǔn)輸入流有一個(gè)參數(shù)的get函數(shù):調(diào)用形式為:cin.get(ch)。作用是從輸入流中讀取一個(gè)字符,并賦給變量ch。#include<iostream.h>intmain(){charc;cout<<"inputeasectence,please:"<<endl;while(cin.get(c)){cout.put(c);}cout<<"end"<<endl;return0;}第40頁,共63頁,2024年2月25日,星期天7.3標(biāo)準(zhǔn)輸入流有三個(gè)參數(shù)的get函數(shù):調(diào)用形式:

cin.get(字符數(shù)組/字符指針,字符個(gè)數(shù)n,終止字符) 其作用是,從輸入流中讀取n-1個(gè)字符,并賦給指定的數(shù)組(或指針指向的數(shù)組)。如果在讀取中遇見終止字符,則提前結(jié)束讀取操作。#include<iostream.h>intmain(){charch[20];cout<<"inputeasectence,please:"<<endl;cin.get(ch,18,'\n');cout<<ch<<endl;return0;}第41頁,共63頁,2024年2月25日,星期天7.3標(biāo)準(zhǔn)輸入流用成員函數(shù)getline讀入一行字符。調(diào)用形式:

getline(字符數(shù)組/字符指針,字符個(gè)數(shù)n,終止字符)

作用是從讀入流中讀取一行字符,并賦給字符數(shù)組。第42頁,共63頁,2024年2月25日,星期天7.3標(biāo)準(zhǔn)輸入流istream類其它成員函數(shù)eof函數(shù):表示文件結(jié)束。從輸入流中讀入文件,當(dāng)達(dá)到文件尾,則eof函數(shù)值為非0(表示真),否則為0(假)。#include<iostream.h>intmain(){charc;while(!cin.eof())if((c=cin.get())!='')cout.put(c);elsecout.put('_');return0;}第43頁,共63頁,2024年2月25日,星期天7.4文件操作與文件流文件的概念:文件一般是指存儲(chǔ)在外部介質(zhì)上的數(shù)據(jù)集合。我們主要是指數(shù)據(jù)文件。根據(jù)數(shù)據(jù)的組織形式,數(shù)據(jù)文件分為:ASCII文件:又稱為文本文件,它的每一個(gè)字節(jié)放一個(gè)ASCII代碼,代表一個(gè)字符。二進(jìn)制文件:又稱為內(nèi)部格式文件,它把數(shù)據(jù)按其在內(nèi)存中的存儲(chǔ)形式遠(yuǎn)洋輸出到磁盤上存放。 對(duì)于字符信息,在內(nèi)存中是以ASCII代碼形式存放的,因此,無論用ASCII文件輸出,還是用二進(jìn)制文件輸出,其數(shù)據(jù)形式是一樣的。但是對(duì)于數(shù)值數(shù)據(jù),二者是不同的。第44頁,共63頁,2024年2月25日,星期天7.4文件操作與文件流文件流類與文件流對(duì)象:文件流是以外存文件為輸入輸出對(duì)象的數(shù)據(jù)流。輸出文件流是從內(nèi)存流向外存文件的數(shù)據(jù);輸入文件流是從外存文件流向內(nèi)存的數(shù)據(jù)。文件與文件流的區(qū)別:文件流不是文件,而只是以文件為輸入輸出對(duì)象的流。C++定義的文件類:

ifstream類,是istream類派生,用于從磁盤文件輸入數(shù)據(jù)。

ofstream是ostream類派生,用于向磁盤文件的輸出。

fstream是iostream類的派生,用于磁盤文件的輸入輸出。第45頁,共63頁,2024年2月25日,星期天7.4文件操作與文件流文件的打開與關(guān)閉打開磁盤文件:打開文件是指在文件讀寫之前做必要的準(zhǔn)備工作。包括:為文件對(duì)象和指定的磁盤文件建立關(guān)聯(lián),以便使文件流流向指定的磁盤文件;指定文件的工作方式,如,是讀文件還是寫文件,是操作ASCII文件還是二進(jìn)制文件。 打開文件有兩種實(shí)現(xiàn)方式:調(diào)用文件流的成員函數(shù)open。一般形式為:

文件流對(duì)象.open(磁盤文件名,輸入輸出方式); 注意,磁盤文件名可以包括路徑,省略路徑則默認(rèn)為當(dāng)前目錄。如:

ofstreamoutfile;

//定義ofstream類對(duì)象outfile

outfile.open(“fi.dat,ios::out);

//使文件流與f1.dat文件建立關(guān)聯(lián)第46頁,共63頁,2024年2月25日,星期天7.4文件操作與文件流在定義文件流對(duì)象時(shí)指定參數(shù):比如

ostreamoutfile(“f1.dat”,ios::out);一般常用這種形式來打開文件。第47頁,共63頁,2024年2月25日,星期天7.4文件操作與文件流文件的輸入輸出方式設(shè)置值:方式作用ios::in以輸入方式打開文件ios::out以輸出方式打開文件。若文件存在,則清除原內(nèi)容ios::app以輸出方式打開文件。寫入的數(shù)據(jù)增加在文件末尾ios::ate打開已有文件,文件指針指向文件末尾ios::trunc打開文件,若文件存在,則刪除原數(shù)據(jù)ios::binary以二進(jìn)制方式打開文件ios::in|ios::out以讀寫方式打開文件ios::out|ios::binary以二進(jìn)制方式打開輸出文件ios::in|ios::binar以二進(jìn)制方式打開輸入文件第48頁,共63頁,2024年2月25日,星期天7.4文件操作與文件流關(guān)閉磁盤文件:即解除該磁盤文件與文件流的關(guān)聯(lián)。關(guān)閉文件的成員函數(shù):

outfile.close();

第49頁,共63頁,2024年2月25日,星期天7.5字符串流字符串流的概念:文件流是以外存文件為輸入輸出對(duì)象的數(shù)據(jù)流,而字符串流是將數(shù)據(jù)輸出到內(nèi)存中的字符數(shù)組,或從字符數(shù)組讀入數(shù)據(jù)。字符串流也稱內(nèi)存流。字符串流緩沖區(qū):字符串流也有緩沖區(qū)。一開始,緩沖區(qū)為空。如果向字符數(shù)組存入數(shù)據(jù),隨著向流插入數(shù)據(jù),流緩沖區(qū)中的數(shù)據(jù)不斷增加。當(dāng)緩沖區(qū)滿或遇到換行符,緩沖區(qū)內(nèi)容變?nèi)看嫒胱址麛?shù)組。如果是從字符數(shù)組讀數(shù)據(jù),先將字符數(shù)組中的數(shù)據(jù)送到緩沖區(qū),然后從緩沖區(qū)提取數(shù)據(jù)賦給有關(guān)變量。第50頁,共63頁,2024年2月25日,星期天7.5字符串流 數(shù)據(jù)存入字符數(shù)組之前,先要將數(shù)據(jù)轉(zhuǎn)換成ASCII代碼,然后放入緩沖區(qū),再從緩沖區(qū)送到字符數(shù)組。 字符串流類的類型有:Istrstream類;Ostrstream類;Strstream類。 文件流類和字符串流類都是ostream類、istream類和iostream類的派生類。

第51頁,共63頁,2024年2月25日,星期天7.5字符串流建立輸出字符串流對(duì)象:ostrstream類提供的構(gòu)造函數(shù)原型為:

ostrstream::ostrstream(char*buffer, intn, intmode=ios::out);其中:buffer是指向字符數(shù)組首元素的指針;n為指定的流緩沖區(qū)大小,一般與字符數(shù)組大小相同;第三個(gè)參數(shù)可選,默認(rèn)為ios:;out方式,可以用以下語句建立輸出字符串流對(duì)象并與字符數(shù)組建立關(guān)聯(lián):

ostrstreamstrout(ch1,20); 作用是建立輸出字符串流對(duì)象strout與字符數(shù)組ch1關(guān)聯(lián),緩沖區(qū)大小為20。第52頁,共63頁,2024年2月25日,星期天7.5字符串流建立輸入輸出字符串流對(duì)象:strstream類提供的構(gòu)造函數(shù)原型為:

strstream::strstream(char*buffer, intn, intmode);

可以用以下語句建立輸入輸出字符流對(duì)象:

strstreamstrio(ch3,sizeof(ch3),ios::in|ios::out);

作用是建立輸入輸出字符串流對(duì)象,以字符數(shù)組ch3為輸入輸出對(duì)象,流緩沖區(qū)大小與ch3相同。第53頁,共63頁,2024年2月25日,星期天7.5字符串流例:將三個(gè)學(xué)生數(shù)據(jù)保存在字符數(shù)組中。#include<iostream>#include<strstream>usingnamespacestd;structstudent{intnum;charname[10];intscore;};voidmain(){studentstud[3]={1001,"Li",78,1002,"Liu",98,1003,"Ge",90};charc[50];

ostrstreamstrout(c,30);for(inti=0;i<3;i++)

strout<<stud[i].num<<stud[i].name<<stud[i].score;strout<<ends;cout<<"arrayc:"<<c<<endl;}第54頁,共63頁,2024年2月25日,星期天Object-Oriented

Programming

inC++

第八章C++工具第55頁,共63頁,2024年2月25日,星期天8.1命名空間8.2使用早期的函數(shù)庫第56頁,共63頁,2024年2月25日,星期天8.1命名空間 本課程的各章節(jié)的程序中,都用到了這樣的語句:

usingnamespacstd;

這就是命名空間std。為什么需要命名空間?C語言定義了3個(gè)作用域,即文件域,函數(shù)域和復(fù)合語句域。C++又引入了類作用域。 不同的作用域中可以用相同的變量名,互不干擾。但是,如果是在不同的庫文件(*.h)中,有相同的變量名和類名,而不巧又在被一個(gè)程序包含、主文件中又調(diào)用了該變量,定義了該類對(duì)象,于是引起矛盾沖突。第57頁,共63頁,2024年2月25日,星期天8.1命名空間什么是命名空間?為了解決這個(gè)問題,ANSIC++增加了命名空間的概念。簡單地說,就是ANSIC++引入的,可以由用戶命名的內(nèi)存區(qū)域,把一些全局實(shí)體分別放在各個(gè)命名空間中,從而與其他全局實(shí)體分隔開來。比如:

namespacensl {inta; doubleb; }其中:namespace是定義命名空間的關(guān)鍵字;nsl是用戶指定的空間名。花括號(hào)內(nèi)包含的a,b,是命名空間成員。第58頁,共63頁,2024年2月25日,星期天8.1命名空間 注意a和b仍然是全局變量,僅僅把它們隱藏在命名空間中,而程序中如果要使用變量a和b,必須加上空間名和域分辨符。如:nsl::a,nsl::b等。這些名字稱為被限定名。

C++中的命名空間和被限定名的關(guān)系,類似與操作系統(tǒng)中文件夾和其中文件的關(guān)系。命名空間的作用:是建立一些互相分隔的作用域,把一些全局實(shí)體分割開來,以免產(chǎn)生名字沖突。命名空間中的被限定名可以是:常量和變量(可以帶有初始化);函數(shù)(可以是定義或聲明);結(jié)構(gòu)體或類;模板或另一個(gè)命名空間(意

溫馨提示

  • 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)論