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

下載本文檔

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

文檔簡介

面向?qū)ο蟪绦蛟O(shè)計之多態(tài)性與虛函數(shù)第一頁,共六十三頁,編輯于2023年,星期二6.1多態(tài)性的概念 多態(tài)性(polymorphism)是面向?qū)ο蟪绦蛟O(shè)計的重要特征。一個算法語言如果只支持類,而不支持多態(tài),只能說是基于對象的語言,如Ada,VB。C++支持多態(tài)性,在C++程序設(shè)計中能夠?qū)崿F(xiàn)多態(tài)性。利用多態(tài)性,可以設(shè)計和擴(kuò)展一個易于擴(kuò)展的系統(tǒng)。什么叫多態(tài)?多態(tài)的意思是一種事物的多種形態(tài)。在C++中,是指具有不同功能的函數(shù)可以用同一個函數(shù)名。面向?qū)ο蠓椒ㄖ幸话闶沁@樣描述多態(tài)性的:向不同的對象發(fā)送同一個消息,不同的對象在接收時會產(chǎn)生不同的行為(即方法)。 第二頁,共六十三頁,編輯于2023年,星期二寫出程序運行結(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();}

第三頁,共六十三頁,編輯于2023年,星期二6.1多態(tài)性的概念 我們其實已經(jīng)接觸過多態(tài)性的現(xiàn)象。如函數(shù)的重載多態(tài)性分類:從系統(tǒng)實現(xiàn)的角度看,多態(tài)性分為以下兩類:靜態(tài)多態(tài)性:又稱編譯時的多態(tài)性。如函數(shù)重載屬于靜態(tài)多態(tài)性。動態(tài)多態(tài)性:有稱為運行時的多態(tài)性。它主要表現(xiàn)為虛函數(shù)(virtualfunction)。第四頁,共六十三頁,編輯于2023年,星期二6.3虛函數(shù)

能否用一個調(diào)用形式,既能調(diào)用派生類的函數(shù),又能調(diào)用基類同名函數(shù)?C++中的虛函數(shù)就是用來解決這一問題。虛函數(shù)的作用:虛函數(shù)的作用是允許在派生類中重新定義與基類同名的函數(shù),并且可以通過基類指針或引用來訪問基類和派生類中的同名函數(shù)。第五頁,共六十三頁,編輯于2023年,星期二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();//指向基類對象s1pt=&g1;pt->display();//指向派生類對象g1,僅輸出了派生類的基類數(shù)據(jù)成員,因為它調(diào)用的是基類成員函數(shù)display!}假如想輸出派生類的全部數(shù)據(jù),當(dāng)然可以采用下面兩種方法之一:通過派生類對象名g1,調(diào)用派生類對象的成員函數(shù):g1.display();定義一個指向派生類的指針ptr,并指向g1,然后用ptr->display()。第六頁,共六十三頁,編輯于2023年,星期二6.3虛函數(shù) 我們可以用虛函數(shù)可以順利解決這一問題。方法是:在基類student中聲明display函數(shù)時,在最左邊加上一個關(guān)鍵字virtual:

virtualvoiddisplay();

就可以student類的display函數(shù)聲明為虛函數(shù),程序其它部分不變編譯運行后,可見,使用pt->display(),的確將graduate類對象g1的全部數(shù)據(jù)顯示了出來,說明它調(diào)用的是g1的成員函數(shù)display。在派生類中重新定義該函數(shù),要求函數(shù)名、函數(shù)類型、參數(shù)表完全相同。但不加virtual關(guān)鍵字。只在類里的成員函數(shù)聲明時,加上關(guān)鍵字virtual,在類外定義定義虛函數(shù)時,不加virtual關(guān)鍵字。定義一個指向基類對象的指針,并使她指向同一類中的某一對象;通過該指針標(biāo)量調(diào)用此虛函數(shù),此時調(diào)用的就是指針變量指向的對象的同名函數(shù),而不是基類的同名函數(shù)!第七頁,共六十三頁,編輯于2023年,星期二6.3虛函數(shù) 通過使用虛函數(shù)和指針,就能方便地調(diào)用同一類族中不同類對象的同名函數(shù),只要先用基類指針指向該對象即可。#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();//指向基類對象s1pt=&g1;pt->display();//指向派生類對象g1,調(diào)用g1的顯示函數(shù)display,打印出g1全部數(shù)據(jù)成員}第八頁,共六十三頁,編輯于2023年,星期二6.3虛函數(shù) 將函數(shù)重載與虛函數(shù)比較,可見:函數(shù)重載是解決的是同一層次上的同名函數(shù)的問題。是橫向重載。虛函數(shù)解決的是不同派生層次上的同名函數(shù)的問題。相當(dāng)于縱向重載。同一類族的虛函數(shù)的首部是相同的;而重載函數(shù)的首部不相同(參數(shù)表不能相同)。第九頁,共六十三頁,編輯于2023年,星期二6.3虛函數(shù)靜態(tài)關(guān)聯(lián)與動態(tài)關(guān)聯(lián)

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

//指針為指向基類對象指針,

//但實際指向臨時派生類對象deletep;return0;}第十四頁,共六十三頁,編輯于2023年,星期二6.3虛函數(shù) 實際上,程序只析構(gòu)了基類對象,而沒有析構(gòu)派生類對象,為什么呢?因為指針p為基類指針,系統(tǒng)認(rèn)為它只有基類對象,而與派生類對象無關(guān)。實際上,由于該指針被指向了一個臨時派生類對象,所以還應(yīng)該這個臨時的析構(gòu)派生類對象。解決的辦法:可以將基類的析構(gòu)函數(shù)聲明為虛析構(gòu)函數(shù)。如:

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

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

virtualfloatarea()const{return0;}

其返回0表示“點”沒有面積。其實,在基類中并不使用這個函數(shù),其返回值也沒有意義。第十六頁,共六十三頁,編輯于2023年,星期二6.4純虛函數(shù)與抽象類 為簡化起見,可以不寫出這種無意義的函數(shù)體,只給出函數(shù)的原型,并在后面加上“=0”,如:

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

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

第二十頁,共六十三頁,編輯于2023年,星期二編程練習(xí):

定義虛函數(shù),基類為SHAPE,派生出圓形、矩形、三角形類。第二十一頁,共六十三頁,編輯于2023年,星期二#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;};第二十二頁,共六十三頁,編輯于2023年,星期二#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;};第二十三頁,共六十三頁,編輯于2023年,星期二續(xù):定義一個函數(shù)printArea,以對象為形參,輸出三種形狀的面積

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

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

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

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

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

Programming

inC++

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

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

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

strstreamstrstreamstrstream輸入字符串流類輸出字符串流類輸入輸出字符串流類istrstreamostrstreamstrstreamfstreamfstreamfstream輸入文件流類輸出文件流類輸入輸出文件流類ifstreamofstreamfstreamiostreamiostreamiostream通用輸入流和其他輸入流的基類通用輸出流和其他輸出流的基類通用輸入輸出流和其他輸入輸出流的基類istreamostreamiostreamIostream抽象基類ios在哪個頭文件中聲明作用類名第三十三頁,共六十三頁,編輯于2023年,星期二7.1C++的輸入和輸出iostream文件中定義的4種流對象stderrostream_withassign屏幕標(biāo)準(zhǔn)錯誤流clogstderrostream_withassign屏幕標(biāo)準(zhǔn)錯誤流cerrstdoutostream_withassign屏幕標(biāo)準(zhǔn)輸出流coutstdinistream_withassign鍵盤標(biāo)準(zhǔn)輸入流cinC語言對應(yīng)文件對應(yīng)的類對應(yīng)設(shè)備含義對象說明

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

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

cerr和clog相似,均為向顯示器輸出出錯信息第三十四頁,共六十三頁,編輯于2023年,星期二7.2標(biāo)準(zhǔn)輸出流clog流對象:也是標(biāo)準(zhǔn)出錯流,是consolelog的縮寫。作用和cerr相同。區(qū)別在于,cerr不經(jīng)過緩沖區(qū),直接向顯示器輸出,而clog經(jīng)過緩沖區(qū),緩沖區(qū)裝滿后或遇到endl時,向顯示器輸出。#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;}}第三十五頁,共六十三頁,編輯于2023年,星期二7.2標(biāo)準(zhǔn)輸出流格式輸出:輸出數(shù)據(jù)時,為簡便起見往往不指定輸出格式。但也可以指定輸出格式。 輸出格式有兩種方法:①使用控制符輸出格式;②使用流對象的有關(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ù)精度為n位setw(n)設(shè)置字段寬度為nsetiosflags(ios::left/right)輸出數(shù)據(jù)左/右對齊resetioflags()終止已設(shè)置的輸出格式,在括號中指定內(nèi)容第三十六頁,共六十三頁,編輯于2023年,星期二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;}第三十七頁,共六十三頁,編輯于2023年,星期二7.2標(biāo)準(zhǔn)輸出流用流成員函數(shù)put輸出字符 我們已經(jīng)知道,程序中一般用cout<<實現(xiàn)輸出,cout流在內(nèi)存中有相應(yīng)的緩沖區(qū)。 有時,我們想只輸出一個字符,ostream類提供了put成員函數(shù)來滿足這一特殊需求:#include<iostream.h>intmain(){char*a="BASIC";for(inti=4;i>=0;i--)cout.put(*(a+i));cout.put('\n');return0;}第三十八頁,共六十三頁,編輯于2023年,星期二7.3標(biāo)準(zhǔn)輸入流cin流:cin流是istream類的對象。它從標(biāo)準(zhǔn)輸入設(shè)備(鍵盤)獲取數(shù)據(jù),程序中的變量通過流提取符“>>”從流中提取數(shù)據(jù)。用于字符輸入的流成員函數(shù):用get函數(shù)讀入一個字符:get函數(shù)有三中形式:無參數(shù)、有一個參數(shù)和3個參數(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;}第三十九頁,共六十三頁,編輯于2023年,星期二7.3標(biāo)準(zhǔn)輸入流有一個參數(shù)的get函數(shù):調(diào)用形式為:cin.get(ch)。作用是從輸入流中讀取一個字符,并賦給變量ch。#include<iostream.h>intmain(){charc;cout<<"inputeasectence,please:"<<endl;while(cin.get(c)){cout.put(c);}cout<<"end"<<endl;return0;}第四十頁,共六十三頁,編輯于2023年,星期二7.3標(biāo)準(zhǔn)輸入流有三個參數(shù)的get函數(shù):調(diào)用形式:

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

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

作用是從讀入流中讀取一行字符,并賦給字符數(shù)組。第四十二頁,共六十三頁,編輯于2023年,星期二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;}第四十三頁,共六十三頁,編輯于2023年,星期二7.4文件操作與文件流文件的概念:文件一般是指存儲在外部介質(zhì)上的數(shù)據(jù)集合。我們主要是指數(shù)據(jù)文件。根據(jù)數(shù)據(jù)的組織形式,數(shù)據(jù)文件分為:ASCII文件:又稱為文本文件,它的每一個字節(jié)放一個ASCII代碼,代表一個字符。二進(jìn)制文件:又稱為內(nèi)部格式文件,它把數(shù)據(jù)按其在內(nèi)存中的存儲形式遠(yuǎn)洋輸出到磁盤上存放。 對于字符信息,在內(nèi)存中是以ASCII代碼形式存放的,因此,無論用ASCII文件輸出,還是用二進(jìn)制文件輸出,其數(shù)據(jù)形式是一樣的。但是對于數(shù)值數(shù)據(jù),二者是不同的。第四十四頁,共六十三頁,編輯于2023年,星期二7.4文件操作與文件流文件流類與文件流對象:文件流是以外存文件為輸入輸出對象的數(shù)據(jù)流。輸出文件流是從內(nèi)存流向外存文件的數(shù)據(jù);輸入文件流是從外存文件流向內(nèi)存的數(shù)據(jù)。文件與文件流的區(qū)別:文件流不是文件,而只是以文件為輸入輸出對象的流。C++定義的文件類:

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

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

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

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

ofstreamoutfile;//定義ofstream類對象outfile

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

//使文件流與f1.dat文件建立關(guān)聯(lián)第四十六頁,共六十三頁,編輯于2023年,星期二7.4文件操作與文件流在定義文件流對象時指定參數(shù):比如

ostreamoutfile(“f1.dat”,ios::out);一般常用這種形式來打開文件。第四十七頁,共六十三頁,編輯于2023年,星期二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)制方式打開輸入文件第四十八頁,共六十三頁,編輯于2023年,星期二7.4文件操作與文件流關(guān)閉磁盤文件:即解除該磁盤文件與文件流的關(guān)聯(lián)。關(guān)閉文件的成員函數(shù):

outfile.close();

第四十九頁,共六十三頁,編輯于2023年,星期二7.5字符串流字符串流的概念:文件流是以外存文件為輸入輸出對象的數(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)變量。第五十頁,共六十三頁,編輯于2023年,星期二7.5字符串流 數(shù)據(jù)存入字符數(shù)組之前,先要將數(shù)據(jù)轉(zhuǎn)換成ASCII代碼,然后放入緩沖區(qū),再從緩沖區(qū)送到字符數(shù)組。 字符串流類的類型有:Istrstream類;Ostrstream類;Strstream類。 文件流類和字符串流類都是ostream類、istream類和iostream類的派生類。

第五十一頁,共六十三頁,編輯于2023年,星期二7.5字符串流建立輸出字符串流對象:ostrstream類提供的構(gòu)造函數(shù)原型為:

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

ostrstreamstrout(ch1,20); 作用是建立輸出字符串流對象strout與字符數(shù)組ch1關(guān)聯(lián),緩沖區(qū)大小為20。第五十二頁,共六十三頁,編輯于2023年,星期二7.5字符串流建立輸入輸出字符串流對象:strstream類提供的構(gòu)造函數(shù)原型為:

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

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

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

作用是建立輸入輸出字符串流對象,以字符數(shù)組ch3為輸入輸出對象,流緩沖區(qū)大小與ch3相同。第五十三頁,共六十三頁,編輯于2023年,星期二7.5字符串流例:將三個學(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;}第五十四頁,共六十三頁,編輯于2023年,星期二Object-Oriented

Programming

inC++

第八章C++工具第五十五頁,共六十三頁,編輯于2023年,星期二8.1命名空間8.2使用早期的函數(shù)庫第五十六頁,共六十三頁,編輯于2023年,星期二8.1命名空間 本課程的各章節(jié)的程序中,都用到了這樣的語句:

usingnamespacstd;

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

namespacensl {inta; doubleb; }其中:namespace是定義命名空間的關(guān)鍵字;nsl是用戶指定的空間名?;ɡㄌ杻?nèi)包含的a,b,是命名空間成員。第五十八頁,共六十三頁,編輯于2023年,星期二8.1命名空間 注意a和b仍然是全局變量,僅僅把它們隱藏在命名空間中,而程序中如果要使用變量a和b,必須加上空間名和域分辨符。如:nsl::a,nsl::b等。這些名字稱為被限定名。

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

溫馨提示

  • 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)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論