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