C++笔记 4
1、類和對象
?? 類就是對對象的描述,主要從屬性和行為兩個方面描述。
?? 對于屬性一般作成private , 行為作為public
?? 函數(shù) (1)構(gòu)造函數(shù),初始化所有的成員變量,系統(tǒng)自動調(diào)用,可以重載
??????? (2)析構(gòu)函數(shù),在對象生命周期結(jié)束的時候自動被調(diào)用調(diào)用,不準重載
?????????????? 構(gòu)造函數(shù)和析構(gòu)函數(shù)都是系統(tǒng)自動調(diào)用的,析構(gòu)函數(shù)可以通過對象調(diào)用??
?????????????? A a;
?????????????? a.A();?? //error 構(gòu)造函數(shù)是不能手工調(diào)用的
?????????????? a.~A();? //right 手工調(diào)用析構(gòu)函數(shù)時,會被當(dāng)作一個普通的成員函數(shù)調(diào)用,其中的代碼會被執(zhí)行,對象不被銷毀
??????? (3)get,set方法? 用于訪問私有的成員變量的,外界訪問變量的唯一通道
??????? (4)類本身的行為 是我們在編碼時要下功夫的地方
2、類的組成
?? (1)數(shù)據(jù)部分
?? (2)構(gòu)造函數(shù)和析構(gòu)函數(shù)
?? (3)get & set方法
?? (4)業(yè)務(wù)方法
??
3、棧的實現(xiàn)(存儲int類型的棧)??????????????????????????
?? 要想實現(xiàn),需要一個數(shù)組做容器,保存用戶插入的數(shù)據(jù),用指針實現(xiàn); int *p;
???????????? 還需要一個變量,保存棧頂位置?? int top;?? //top從0開始
???????????? 對于棧不能無限制的存數(shù)據(jù),所以需要一個int類型的變量來記載數(shù)組的最大長度?? int max;
?? (1)構(gòu)造函數(shù)
??????? 當(dāng)不給參數(shù)的時候,棧的長度是默認值Stack();也可以用戶指定長度Stack(int)
?? (2)析構(gòu)函數(shù)
??????? 一定要有,因為要在堆中申請空間
?? (3)為保護棧數(shù)據(jù)的安全,對p不能提供get,set 方法
??????? 對于top,max的值,取決于插入的數(shù)據(jù),所有只能有g(shù)et方法,不能設(shè)置,不需要有set方法
?? (4)int push(int);? 插入,當(dāng)棧滿的時候,返回-1,表示插入失敗
??????? int pop();????? 刪除棧頂?shù)脑?#xff0c;如果正確刪除一個數(shù)據(jù),返回數(shù)據(jù)的值,若沒有正確刪除,返回-1,表示??樟?br />??????? void disp();??? 現(xiàn)實數(shù)據(jù)
?? (5)實現(xiàn)的時候,注意:
??????? 在函數(shù)名前加 " Stack:: "
?? (6)在棧中插入數(shù)據(jù),就是在top的位置插入數(shù)據(jù)
????????????? 刪除數(shù)據(jù),就是把棧頂下移一個位置
?????????????
4、繼承
?? (1)繼承表現(xiàn)一種" is a " 的關(guān)系。Teacher extend Person
??????? 其中Teacher是子類,Person是父類
??????? 子類繼承父類的所有屬性和行為
?? (2)class Teacher:public Person{};
???????? 表示Teacher類繼承Person類???????
??
?? 在extends_sample2中,子類可以直接使用父類的teach函數(shù),但是不能使用父類private的name屬性。name屬性實際上存在在子類中,但是不能被子類直接使用,因為是private屬性。private屬性只能被本對象的函數(shù)訪問,public的屬性可以被子類直接使用,但是外部函數(shù)也可以訪問public權(quán)限的屬性。既想被子類使用又不想讓外部函數(shù)訪問,怎么辦哪?使用protected修飾屬性就可以了。
???? 下面是一個類的屬性具有不同的訪問控制修飾符在不同的對象中的可見性i(可見性就是可以訪問):???
???????????????? 本對象? 子類對象? 其他函數(shù)
?private屬性????? 可見??? 不可見???? 不可見
?protected屬性??? 可見???? 可見????? 不可見
?public屬性?????? 可見???? 可見?????? 可見
??? 在繼承關(guān)鍵字extends前面也有三種不同的訪問控制修飾符號,被不同的繼承方式繼承后訪問控制權(quán)限會發(fā)生變化。可以把繼承方式理解成城門。無論外邊的人多么胖,想通過不同寬度的城門只能減肥到相應(yīng)的寬度才可以。
????????????????????? public extends?????? protected extends?????? private extends
父類的private屬性?????? 不能訪問?????????????? 不能訪問????????????????? 不能訪問
父類的protected屬性? 變成protected???????????????? 不變???????????? 變成private,子類可以訪問,子類的子類不能訪問
父類的public屬性????????? 不變?????????????? 變成protected????????? 變成private,子類可以訪問,子類的子類不能訪問
??? 構(gòu)造函數(shù)不能被繼承。因為構(gòu)造函數(shù)只是適合于本類的產(chǎn)生方式。
??? 如extends_sample4,創(chuàng)建子類的時候需要首先創(chuàng)建父類。怎么理解哪?
??? 考慮子類的構(gòu)成,就像cs中的匪徒用的46是由ak47添加上瞄準鏡組成的。
??? 創(chuàng)建子類的時候會首先調(diào)用父類的構(gòu)造函數(shù),因為繼承的時候沒有指定繼承時使用的父類的構(gòu)造函數(shù)。
??? 構(gòu)造函數(shù)有很多種,因為沒有指定構(gòu)造函數(shù),就會默認使用無參的構(gòu)造函數(shù)。如果父類沒有無參的構(gòu)造函數(shù),那么就會出現(xiàn)編譯錯誤。
??? 這是問題的產(chǎn)生,如何解決哪?
??? 可以在父類中添加無參構(gòu)造函數(shù)。如果我們不是父類的設(shè)計者,就應(yīng)該在子類繼承的時候指定使用父類的那個構(gòu)造函數(shù)。
??? 如在寫子類構(gòu)造函數(shù)時,使用這種形式Teacher(char* name, int age, double salary):Person(name,age){......},就可以指定使用父類的有參構(gòu)造函數(shù)。
??? 構(gòu)造時候是先父類后子類。析構(gòu)函數(shù)哪?析構(gòu)函數(shù)不能被繼承。子類釋放的時候,首先調(diào)用自身的析構(gòu)函數(shù),再調(diào)用父類的析構(gòu)函數(shù)。這與構(gòu)造函數(shù)的調(diào)用順序相反。
5、在子類中可以修改父類的行為,叫方法的覆蓋
?? (1)在子類中的函數(shù)名必須與父類的一樣
?? (2)隱藏,無法產(chǎn)生多態(tài)
??????? class Base{
??????? public:
?????????? void fn( int a ){
????????????? cout<<"Base a = " << a << endl;
????????? }
??????? };
??????? class Sub:public Base{
??????? public:
?????????? void fn(? ){
????????????? cout<<"Sub b = 20" << endl;
?????????? }
??????? };
??? (3)調(diào)用父類的方法
????????? a.Base::fn(10);? //可以有針對性的調(diào)用父類的函數(shù)
?????????
6、函數(shù)的高內(nèi)聚,低耦合
?? 高內(nèi)聚:函數(shù)的功能盡量單一,這樣的代碼可維護性高
?? 低耦合:避免修改函數(shù)的時候,產(chǎn)生連鎖反映。
??
7、多態(tài)
?? (1)什么是多態(tài)?
??????? 一個int類型的指針,只能指向一個int類型的變量
??????? 對于對象來講Person類型的指針 ,能指向Person類型的對象
??????? Person類型的指針能指向一個Teacher(extend Person)類型的對象
???????
?? (2)多態(tài)的特征:
??????? 父類的指針可以指向子類的對象
??????? 通過父類指針只能調(diào)用父類中聲明的方法
??????? 通過指針調(diào)用函數(shù)的時候,若函數(shù)是個虛函數(shù),表現(xiàn)出來的行為是對象自身的行為
???????
??????? Person *p = new Teacher ;
??????? 編譯時類型???? 運行時類型
???????
?? (3)子類的指針不能指向父類對象
??????? 因為子類中會有子類特有的函數(shù),運行時不能通過指針調(diào)用子類特有的函數(shù)
???????
?? (4)" virtual "父類函數(shù)的返回值前加此關(guān)鍵字,則為虛函數(shù)
??
?? (5)產(chǎn)生多態(tài)的必要前提:
??????? 繼承,方法覆蓋,虛函數(shù)
???????
8、虛函數(shù)的實現(xiàn)原理
? 在每個對象中都有一個虛函數(shù)列表的指針,虛函數(shù)列表是一個棧。
? 在構(gòu)造對象時,根據(jù)先構(gòu)造父類,再構(gòu)造子類的原則,父類的函數(shù)先入棧,在子類中覆蓋的函數(shù)放在上面。
? 等對象構(gòu)造完畢時,子類的函數(shù)在最上面,根據(jù)棧后進先出的原則,先調(diào)用的是子類函數(shù)
9、在釋放資源的時候
?? delete p ;
?? 只會調(diào)用Person類的析構(gòu)函數(shù),因為指針的類型是Person的,這樣會造成子類的空間得不到及時的釋放,會造成內(nèi)存泄露
?? 把析構(gòu)函數(shù)也寫成虛函數(shù),這樣就會先調(diào)用子類的析構(gòu)函數(shù),再析構(gòu)父類的析構(gòu)函數(shù)
??
?? 在繼承關(guān)系中,父類的析構(gòu)函數(shù)必須是虛函數(shù)!!!???????
??????????????????????
10、多態(tài)的使用
?????????????????? #include <iostream>
??using namespace std;
??
??class Person{
??public:
???virtual double buy(){?????????
????return 2 ;
???}
??};
??
??class Teacher : public Person{
??public:
???virtual double buy(){
????return 1 ;
???}
??};
??
??class Student : public Person{
??public:
???virtual double buy(){
????return 0.5 ;
???}
??};
??
??class CEO : public Person{
??public:
???virtual double buy(){
????return 1000 ;
???}
??};
??
??void shoufei( Person * p ){
???cout<< p->buy() << endl;
??}
??
??
??int main(){
???Person p ;
???Teacher t ;
???Student s ;
???CEO c ;
??
???shoufei( &p ) ;??? //通過傳入不同對象的地址,調(diào)用相應(yīng)的函數(shù)
???shoufei( &t ) ;??? //與if...else對比
???shoufei( &s ) ;??? //寫程序要盡量少改動寫好的源碼,這樣實現(xiàn)代碼的通用及低耦合
???shoufei( &c ) ;
??
???return 0 ; ?
??}??????????????????????????????
?????????????
作業(yè):寫一個校車類,用數(shù)組裝乘客Bus
????? Bus : 上車,下車 , 賣票等行為
??????????? 車上有Teacher,Student ,計算總票價
?
1、?????????????? 本對象? 子類對象? 其他函數(shù)
?private屬性????? 可見??? 不可見???? 不可見
?protected屬性???? 可見???? 可見????? 不可見
?public屬性???????? 可見???? 可見?????? 可見
?
????????????????????? public extends?????? protected extends?????? private extends
?父類的private屬性?????? 不能訪問?????????????? 不能訪問????????????????? 不能訪問
?父類的protected屬性? 變成protected???????????????? 不變???????????? 變成private,子類可以訪問,子類的子類不能訪問
?父類的public屬性????????? 不變?????????????? 變成protected????????? 變成private,子類可以訪問,子類的子類不能訪問
2、 構(gòu)造函數(shù)有很多種,因為沒有指定構(gòu)造函數(shù),就會默認使用無參的構(gòu)造函數(shù)。如果父類沒有無參的構(gòu)造函數(shù),那么就會出現(xiàn)編譯錯誤。
??? 可以使用這種形式Teacher(char* name, int age, double salary):Person(name,age){......},指定使用父類的有參構(gòu)造函數(shù)。
?
3、多態(tài)的特征:
??????? 父類的指針可以指向子類的對象
??????? 通過父類指針只能調(diào)用父類中聲明的方法
??????? 通過指針調(diào)用函數(shù)的時候,若函數(shù)是個虛函數(shù),表現(xiàn)出來的行為是對象自身的行為
???????????
4、產(chǎn)生多態(tài):(1)指針
???????????? (2)引用
?? 父類的引用可以引用一個子類對象
?? 通過父類引用只能調(diào)用父類函數(shù)
?? 調(diào)用一個父類被覆蓋了的,虛函數(shù),能調(diào)用子類的函數(shù)
??
5、一個子類繼承一個父類? --- 單繼承
?? 一個子類繼承多個父類? --- 多繼承???
??
?? class SpiderMan : public Spider , public Person{....}?????????????????????????????
??
6、菱形繼承,解決重復(fù)元素的沖突
?? 讓兩個父類同時虛繼承一個超類,把多繼承中的重復(fù)元素放在超父類中
?? 當(dāng)有多個子類同時虛繼承一個父類的時候,只有一個子類真正的構(gòu)造父類
?? class Spider : vertual public Animal{.....};
?? class Person : vertual public Animal{.....};
?? class SpiderMan :public Person , public Spider{....};
??
?? 多繼承盡量不要使用三層以上
??
7、抽象類
?? 只有函數(shù)聲明,沒有函數(shù)實現(xiàn)
?? 純虛函數(shù):沒有實現(xiàn)的函數(shù)? virtual void writeLog(char*)=0;
???????????? 若不寫" =0 ",則系統(tǒng)會認為是函數(shù)聲明,會試圖去別的" .cc "文件中去找函數(shù)實現(xiàn)
?? 含有純虛函數(shù)的類稱為抽象類,是抽象數(shù)據(jù)類型,不能創(chuàng)建對象
?? 抽象類型就是為了被別人繼承的,子類覆蓋純虛函數(shù),提供函數(shù)實現(xiàn)
?? 通過父類規(guī)范子類的用法
??
?? 如果子類沒有完全實現(xiàn)抽象父類的所有純虛函數(shù),則認為子類還是一個抽象數(shù)據(jù)類型
??
?? 用到virtual的地方:
?? (1)繼承
?? (2)多繼承
?? (3)純虛函數(shù)
??
?? 抽象類的規(guī)范很重要,在工程中,對于項目的并行開發(fā)很重要
?? 而且對于項目中的改動,能方便的應(yīng)付
?? 用指針指向相應(yīng)的子類對象,方便的調(diào)用子類的函數(shù)
?????
8、友員
?? 針對類來說,自身的私有變量,不能被別的類訪問,但是,如果授權(quán)給一個類為自己的友員,就可以訪問他的私有屬性
?? 可以作為友員的東西:另一個類,一個全局函數(shù)。
??
?? 實現(xiàn)友員的授權(quán):
????? class Girl;
????? class? Person{
?????????? ........
?????????? friend class Girl;? //友員類的聲明-->授權(quán)給Girl類,成為自己的友員,可以訪問自己的私有變量了
????? }
? ----------------------------------------------------------------------------------------------------------------
????? class Girl;
????? class? Person{
?????????? ........
?????????? friend void fn();? //友員函數(shù)的聲明-->授權(quán)給fn函數(shù),成為自己的友員,可以訪問自己的私有變量了
????? }
?????
??? 友員不是類的一部分
??? 若不是互為友員,則不能訪問友員類的私有變量
???
??? 友員的使用:
?????????? Bus把售票員作為自己的友員,訪問自己的私有變量,即裝載乘客的數(shù)組
??????????
??? 友員在項目中的使用
???
9、靜態(tài)數(shù)據(jù)
?? 在類中定義一個靜態(tài)數(shù)據(jù)? (實際上就是一種全局變量)
?? (1)不依賴于對象,在對象不存在之前就已經(jīng)存在了
?? (2)所有對象共享???
??
?? 與全局變量的區(qū)別:
?? (1)使用的類中的靜態(tài)變量,必須通過類名使用
?? (2)而且受訪問控制符號的限制
?? (3)靜態(tài)變量在類中聲明的時候不能賦值,要在類外初始化
??????? class A{
??????? public :
??????????? static int a;
??????? };
??????? int A::a = 100;? //此時才分配空間
??????? int main(){
???????????? cout << A::a <<endl;??? //靜態(tài)變量的用法,不依賴對象,直接使用
??????? }
???????
??? 與成員變量的區(qū)別
??? (1)成員變量依賴與對象,類對象不存在,成員變量也不存在
???????? 靜態(tài)變量不依賴于對象,只要有類聲明,就存在
??? (2)所有對象共享一份靜態(tài)變量
???
10、靜態(tài)函數(shù)
?? 在函數(shù)前加static
?? 不依賴于對象,沒有對象依然可以通過類名調(diào)用靜態(tài)函數(shù)
?? A::fn();
??
?? 在類聲明的時候,靜態(tài)函數(shù)和靜態(tài)變量就存在了
?? 靜態(tài)函數(shù)只能使用靜態(tài)變量,不能使用成員變量
??
11、拷貝構(gòu)造函數(shù)
?? #include <iostream>
?? using namespace std;
?? class Person{
?? public:
????? Person(){ cout<<"Person()"<<endl; }
????? ~Person(){ cout<<"~Person() "<<endl;}
????? void speak(){ cout<<"hello"<<endl; }
?? };
?? void fn( Person p ){? //這里的傳遞時值傳遞,形參是值傳遞,這里的形參的創(chuàng)建是使用拷貝構(gòu)造函數(shù)
????? p.speak();
?? }
?? int main(){
????? Person p ;
????? fn( p ) ;
????? return 0 ;
?? }??
?? 輸出結(jié)果:
?????? Person()
?????? hello
?????? ~Person()
?????? ~Person()???????? //2次析構(gòu),因為其中調(diào)用了的系統(tǒng)提供的拷貝構(gòu)造函數(shù),構(gòu)造出一個新對象
?? 拷貝構(gòu)造函數(shù),以一個已存在的對象為模版創(chuàng)建一個新對象
? 聲明方法: Person(const Person & p){...}? //即節(jié)省空間,又保證模版不會被修改
??
?? 默認拷貝構(gòu)造函數(shù),執(zhí)行的就是簡單的內(nèi)存拷貝 --- 淺拷貝
?? (1)淺拷貝
??????? 只拷貝地址,而不是對指針指向空間的拷貝,會造成2個指針指向同一個空間
?? (2)深拷貝
??????? 為指針創(chuàng)建新空間,拷貝指針指向空間的內(nèi)容
??
?? 調(diào)用拷貝構(gòu)造函數(shù)的時機:????
?? (1)在值傳遞的時候
?? (2)A a;??????? //默認構(gòu)造函數(shù)
??????? A a1 = a;?? //在聲明的時候,用一個對象賦值,使用的是拷貝構(gòu)造函數(shù)
?? (3)A a1;
??????? A a2(a1);?? //顯示的調(diào)用拷貝構(gòu)造函數(shù),傳的參數(shù)是個對象
???????
??? 什么時候需要自己寫拷貝構(gòu)造函數(shù)?
???????? 使用了動態(tài)內(nèi)存,就會面臨淺拷貝的現(xiàn)象,需要自己寫拷貝構(gòu)造函數(shù)
12、運算符重載
???? a1 = a2;
???? 系統(tǒng)調(diào)用了函數(shù) operator=
???? 相當(dāng)于執(zhí)行了這樣的操作:?? a1.operator=(a2);??????
????
???? Student& operator= (const Student &a);
???? 函數(shù)返回左值,返回值為引用
???? 函數(shù)返回右值,返回值為本身
????
???? /*
???? *student a1;
???? *student a2;
???? *a1=a2;? <=>? a1.operator=(a2);
???? */
???? Student& operator= (const Student &a){
????????? age = a.age;
????????? id = a.id;
????????? strcpy(name , a.name);?? //不用new出一塊空間,因為在聲明a1和a2的時候,兩個指針都指向一塊自己的空間,
???????????????????????????????????? 把指針指向的變量拷貝過去,即完成賦值
????????? return *this;
???? }
???? 當(dāng)在堆中申請空間,則覆蓋賦值運算符(" = ")
????
作業(yè):銀行系統(tǒng)的賬戶類
????? 把name , password 改用指針保存
????? (1)析構(gòu)函數(shù)
????? (2)拷貝構(gòu)造
????? (3)重載賦值運算符????
?
?????????????????????
1、拷貝構(gòu)造函數(shù)和運算符重載
? (1)當(dāng)類的成員變量中出現(xiàn)指針類型的時候,需要動態(tài)申請空間,這樣就需要解決淺拷貝的問題
?????? 在聲明對象的同時用另一個對象為其賦值,會調(diào)用拷貝構(gòu)造函數(shù)。
?????? 系統(tǒng)提供的默認拷貝構(gòu)造函數(shù),是淺拷貝,我們可以自己寫一個拷貝構(gòu)造函數(shù),把指針指向的變量也拷貝過去
? (2)類中的成員變量出現(xiàn)指針類型,當(dāng)兩個對象都創(chuàng)建出來了以后,相互賦值的時候,就需要重載賦值運算符號
?????? 手工為指針指向的變量賦值
???????????????????????????????????
2、其他的運算符號重載
?? 對于對象之間的加減操作,系統(tǒng)是不允許的,但通過自己的運算符重載,按照自己的規(guī)則,實現(xiàn)對象之間的運算操作。
?? Integer operator+(const Integer& i){
????????? int t = *p + *(i.p);
????????? Integer temp(t);
????????? return temp;
?? }?????????????????
??
?? (1)自增運算符
????? 前++是左值,返回引用
????? 后++是右值,返回臨時值
?????
????? "++"運算符的優(yōu)先級比"+"高
?????
????? Integer& operator++(){}
????? Integer operator++(int i){}
????? int i是用于區(qū)別前++和后++的,是沒有實際意義的參數(shù),稱為啞元,必須是int類型
?????
????? 前++和后++的操作,主要區(qū)別就是返回的值不同,內(nèi)部都是把變量加1。
????? 前++,(++i)先加后用,返回加1之后的變量值,可以把變量直接加1,就返回,所有可以直接返回引用
????? 后++,(i++)先用后加,返回加1之前的變量值,就是要返回原來的舊值,
???????????? 這樣需要在重載運算符的函數(shù)內(nèi)部創(chuàng)建一個對象保存舊值,再進行加1運算,返回這個舊值本身。
????????????
?? (2)重載"="
?????? 實現(xiàn)用一個int類型給一個Integer對象賦值
?????? Integer& operator=(int i){?? //賦值運算,把對象內(nèi)的int值改變,返回本身即可,所以返回值是引用
??????????????? *p = i;???????????? //手工將int類型的值賦到對象內(nèi)
??????????????? return *this;
?????? }?
??????
?? (3)運算符重載
??????? 不僅可以用類的成員函數(shù)實現(xiàn),也可以用普通函數(shù)實現(xiàn)
??????? 用成員函數(shù)實現(xiàn),參數(shù)只有一個,運算符左邊的是自身,右邊的是參數(shù)? a1.operator=(a2);
??????? 用普通函數(shù)實現(xiàn),參數(shù)需要兩個,第一個參數(shù)是運算符左邊的值,第二個參數(shù)是運算符右邊的值,作為友員函數(shù)重載????????????????????????????????
??????? operator(a1,a2);
?????
?? (4)推薦原則
??????? 所有一元運算符? ---? 成員重載??? "=","[]"只能成員重載
??????? 二元運算符 --- 友員重載
???????
??????? Integer對象類型與int類型相加的時候,
??????? 實現(xiàn) 5+i 而且也能 i+5
??????? 可以用友員重載2次
??????? friend Integer operator+(const Integer& i , int a);
??????? friend Integer operator+(int a , const Integer& i );? //在類中友員函數(shù)的聲明
???????
??? (5)強制類型轉(zhuǎn)換運算符
????????? operator int(){......}? //強轉(zhuǎn)成int類型的聲明?????
?????????
3、流操作符的重載
? (1)輸出流操作符只能使用友員方式重載
?????? friend ostream& operator<< (ostream & o,Integer & i);? //聲明友員函數(shù)
?????? ostream& operator<< (ostream & o ,Integer & i){??????? //實現(xiàn)
??????????? o << *(i.p) ;?????????? //輸出對象內(nèi)的*p,即指針指向的變量
??????????? return o;
?????? }?????????
???????
?????? cout << i ;?? <=>?? operator(cout,i);
??????
?? (2)輸入運算符也能重載,實現(xiàn)對象的讀入,只能使用友員函數(shù)重載
?????? friend istream& operator>> (istream & in,Integer & i);? //聲明友員函數(shù)
?????? istream& operator>> (istream & in ,Integer & i){??????? //實現(xiàn)
??????????? in >> *(i.p) ;????????? //把讀入的數(shù)據(jù)放到*p指向的變量中
??????????? return in;
?????? }???????????
??????
?? (3)為什么只能用友員重載?
??????? 因為cin cout 的位置是固定的,? cin >> i ; cout << i ;
??????? 這樣不能利用對象本身調(diào)用重載的流操作符? i.operator(cout) ->這樣是不正確的
??????? 只能使用友員重載,把對象和cout都當(dāng)做參數(shù)傳進去,這樣就能操作了
???????
練習(xí):賬號類,直接輸出賬號??????????????
????? Account a1;
????? cout << a1 << endl;
?????
?????? friend ostream& operator<< (ostream & o,Account & a);
?????? ostream& operator<< (ostream & o ,Account & a){??????
??????????? o << "Name???? : " << a.name <<endl;
??????????? o << "password : " << a.password << endl;??????????
??????????? o << "id?????? : " << a.id << endl;
??????????? o << "balance? : " << a.balance? ;
???????????
??????????? return o;
?????? }??????
?????
????? friend istream& operator>> (istream & in,Account & a);
?????? istream& operator>> (istream & in ,Account & a){????????
??????????? cout << "enter your name >";
??????????? in >> a.name;???????
??????????? cout << "enter your password >";
??????????? in >> a.password;
??????????? cout << "enter your id >";
??????????? in >> a.id;
??????????? cout << "enter your balance >";
??????????? in >> a.balance;
??????????? return in;
?????? }?????
??????
作業(yè) :
???? 寫一個類叫“rmb”
???? RMB{
??????? int * yuan;
??????? int * jiao;
??????? int * fen;
???????
??????? RMB();
??????? RMB(int y , int j ,int f);
??????? RMB(const RMB & r);
??????? ~RMB();
??????? operator=
??????? friend ostream& operator<< (ostream & o,RMB &r);
??????? friend istream& operator>> (istream & in,RMB &r);
??????? 人民幣之間的運算,及與int的乘法
??????? operator double(){} //強轉(zhuǎn)運算
??????? operator float(){}
???? }?????
?
?1、數(shù)據(jù)? 內(nèi)存中? 變量
???????? 磁盤上? 文件
????????
2、把數(shù)據(jù)從其他的設(shè)備搬到內(nèi)存中 --- 輸入 --- 讀
?? 把內(nèi)存中的數(shù)據(jù)放到其他設(shè)備中 --- 輸出 --- 寫
??
3、流
?? 物質(zhì)的定向移動,輸入輸出流中是數(shù)據(jù)的定向移動
?? 輸入流的源頭 : 文件?????? 目的地:內(nèi)存
?? 輸出流的源頭 : 內(nèi)存?????? 目的地:文件
??
4、標準輸出設(shè)備 --- 顯示器
?? 標準輸入設(shè)備 --- 鍵盤
??
??? 鍵盤 --- 內(nèi)存 --- 顯示器
????????? |??????? |
????? 輸入操作?? 輸出操作???????????
?????
?? 輸入輸出流 : 內(nèi)存與磁盤之間,內(nèi)存與標準輸入輸出設(shè)備之間的?????
??
5、cout? 源 :變量?????? 目的地 :顯示器?
?? cin??????? 鍵盤??????????????? 內(nèi)存中某一變量
??
6、標準輸入流 cin?? istream的一個對象
?? 標準輸出流 cout? ostream的一個對象
?? 標準錯誤流 cerr 目的地都是屏幕,用cout替代
??
7、cin
??? 是一個帶有緩沖的標準的輸入對象,默認輸入設(shè)備是鍵盤
? (1) >>? : 自動校驗數(shù)據(jù)類型??
????????????? 遇到回車才會開始讀數(shù)據(jù),遇到空格就結(jié)束,只能讀一個單詞
????????????? 流是數(shù)據(jù)的定向移動,被讀走的數(shù)據(jù)就消失,沒有讀走的數(shù)據(jù)會一直留在流中,直到流的消失,數(shù)據(jù)也跟著消失
????????????? 流中有數(shù)據(jù),就會阻塞,等待讀取? ---? 所有輸入方法的特性
????????????? 為什么 ">>"可以連續(xù)使用? 因為返回就是istream對象本身的引用
????????????? 注意 : ">>" 不讀回車,不讀空格
? (2)get(): 每次 讀一個字符。返回一個整數(shù),實際上是讀到字符的ASCII碼
??????????????? 把回車,空格都當(dāng)作普通字符讀出來
? (3)get(char&):把讀到的內(nèi)容存到參數(shù)中???????????????
????????????????? cin.get(arr[0]).get(arr[1]);? //get(char&)返回cin本身,可以連續(xù)使用
(4)getline(str,256) : 讀取一行,包括空格
對于回車,只讀走,不保存
會讀取數(shù)組長度減1個字符,最后一個放'\0'
?????????????????? 輸入數(shù)據(jù)超過給定的空間 (1)截斷數(shù)據(jù),剩下的數(shù)據(jù)還在流里
????????????????????????????????????????? (2)設(shè)置一個錯誤標記,調(diào)用cin.clear(),清除錯誤,繼續(xù)工作
???????????????????? #include <iostream>
???????????????????? using namespace std;
???????????????????? int main(){
????????????????????????? int age;
????????????????????????? char name[20] ;
????????????????????????? cout << "enter your age >";
????????????????????????? cin >> age;
????????????????????????? cin.get();??????????? //讀取流中殘余的回車,以便getline能正常工作
????????????????????????? // cin.ignore(20,'\n');? //忽略20個字符或者碰到回車,從流中清除
????????????????????????? cout << "enter your name >";
????????????????????????? cin.getline(name,20);
????????????????????????? cout << "your age is :" << age << endl;
????????????????????????? cout << "your name is :" << name << endl;
???????????????????? }
???????????????????????????????????
? (5)read(char*,int)?? char*是存結(jié)果的地址,int是讀的長度,并且不能比前面的數(shù)組的空間大
???????????????????????? 讀滿為止 ,特殊字符也當(dāng)做普通字符處理
???????????????????????? 超出的部分仍然存在流里面
???????????????????????? 只要數(shù)據(jù)沒讀滿,一直阻塞
???????????????????????? 不會自動補'\0' --- 傳參數(shù)的時候,數(shù)組長度傳減1的長度,補齊'\0'以免亂碼
????????????????????????
?? 所有輸入流的共同特征:只要沒數(shù)據(jù)就阻塞
???????????????????????? 讀不完的就留在流里????????????????????????????????????????
????????????????????????
? (6)cin.ignore(255,'\n')? 忽略255個字符或者遇到'\n',如果在前255個字符中出現(xiàn)'\n',則就忽略到'\n'之前的字符????????????????????????
? (7)peek()? 查看流里的第一個字符是什么
?????????????? 只察看,不讀走
? (8)putback() 向流中插入字符,前提必須有空位的時候
???????????????? 必須與get()一起使用,用get()取出一個字符,才能用putback()插入一個字符
? (9)cin.fail()判斷是否出現(xiàn)錯誤標志,一切正常返回false
?
? 當(dāng)用cin讀取的數(shù)據(jù)類型出現(xiàn)錯誤的時候,這是一種不可恢復(fù)的錯誤,用cin.clear()是不能清除錯誤標記的
? 在鍵盤上讀取,用getline()可以確保輸入流的正常形成,讀取后采取強制轉(zhuǎn)換類型得到自己需要的數(shù)據(jù)
?
8、ifstream
?? (1)需要#include <fstream>頭文件
????? ifstream ifs("test.txt");? //創(chuàng)建一個ifstream的對象,打開文件,給構(gòu)造函數(shù)傳如一個參數(shù),就是文要打開的文件名?
????? //文件的在當(dāng)前目錄下找,也可以用相對路徑或絕對路徑找文件
????? 在打開文件之后,立即判斷打開文件是否成功
????? if( ifs.fail() ){
???????? cout << "Can't open test " <<endl;
???????? return 0;
????? }
?????
????? if( ! ifs ){??? //也可以這樣判斷文件打開是否出錯
???????? cout << "Can't open test " <<endl;
???????? return 0;
????? }
?????
?? (2)在文件結(jié)束的時候都會有"EOF"標志,作為文件結(jié)束的標志符
????? 可以用判斷是否讀到"EOF",來判斷時候讀到文件尾了
????? if(ifs.eof()){
???????? break;
????? }
?????
?? (3)對于一個進程可打開文件的數(shù)量是有數(shù)的,所以文件屬于資源
????? 所以在使用完畢以后,要關(guān)閉文件輸入流?????
?????
?? 練習(xí):(1)把/etc/passwd 文件打印出來
???????? (2)把文件中不以"#"開頭的內(nèi)容讀出來
??????????? peek(),ignore()
???????????
9、輸出操作cout
?? (1) << 操作 被輸出到屏幕上的東西,只所以能輸出,都是以字符串類型輸出
???????????????? 也就是說這個操作有自動類型轉(zhuǎn)換的功能
?? (2)put()?? 返回cout引用,可以連續(xù)調(diào)用???????????
?? (3)write(buf,len)? 按指定長度寫到屏幕上 buf是char*類型
?? (4)cout.width(10); 打印的內(nèi)容總共占10個字符,并靠右對齊
??????????????????????? 只對其后邊的一個cout生效
?? (5)cout.fill('#'); 用'#'補齊空位
??????????????????????? 主要調(diào)用一次,對以后的都生效??????
?? (6)setf()操作,控制格式,教材188頁????????????????????????????????????????
??
?? (7)特殊字符
??????? '\r'? 表示回退一個格,再輸出
??????? '\n'? 回車
??????? \\??? 輸出一個'\',因為'\'會被認為是轉(zhuǎn)義字符
??????? '\t'? 一個tab鍵
???????
?? (8)輸出控制符
??????? oct??? 按八進制輸出? “0”
??????? dec??? 使進制輸出
??????? hex??? 按十六進制輸出 “0x”
??????? flush? 清空緩沖區(qū) 帶緩沖區(qū)是因為和外部設(shè)備交涉,這樣能減少向屏幕輸出的次數(shù),提高效率
?????????????? 回車、程序結(jié)束和flush都是刷新緩存的命令
?????????????? cout << "a" <<flush ;
???????????????
10、ofstream
??? 打開文件,把數(shù)據(jù)寫進文件,關(guān)閉文件???????????????
??? ofstream ofs("ofstream.txt");?? //打開文件,若文件不存在,創(chuàng)建,存在,打開
??? if(ofs.fail()){???????????????? //寫文件失敗,一般是權(quán)限問題
???????? cout << "open file error "<<endl;
???????? return 0;
??? }
???
??? 在iostream頭文件中cin cout對象已經(jīng)被聲明,可以直接使用,因為標準輸入輸出設(shè)備是唯一的,系統(tǒng)聲明
??? 但是fstream的對象要程序員來聲明,因為對文件的輸入輸出是不唯一的
???
???? ofstream ofs("ofstream.txt" , ios::app);? //以追加的形式向文件中寫
???? ios::trunc 默認方式? 把文件內(nèi)容清空,寫新的文件
???? ios::nocreate? 不創(chuàng)建新文件
???? ios::noreplace? 不改寫,要創(chuàng)建新文件
???? 組合多個 ofstream ofs("ofstream.txt" , ios::app | ios::in | ios::binary);
????
11、讀寫二進制文件
??? (1)ios::binary
??? (2)read/write 方法讀寫二進制文件,因為這兩個方法只需要起始位置和大小就可以工作
???
?????
作業(yè):(1)int readInt(){}
?????????? double readDouble(){}
?????????? 強轉(zhuǎn)函數(shù),要求容錯能力強,要求有可靠的手段通知用戶是否出錯????????????????????????????????
????? (2)根據(jù)用戶輸入的用戶名,打印他的用戶id,home,shell,如果用戶不存在,通知用戶
?????????? strtok(),strcmp()??????????
?????
?
?
?
總結(jié)
- 上一篇: 关于code reiview
- 下一篇: Python学习入门基础教程(learn