C++筆記--抽象機制

    •   一個類就是一個用戶定義類型
    •   一個結構體也是一種類。(成員函數),由於不一樣的結構體中可能會有相同的名字的成員函數,因此咱們在定義成員函數的時候就必須給出有關結構體的名字
      void Data::init(int dd,int mm,int yy){}

       

    •   非成員函數禁止訪問私有成員

    •   類中的靜態成員:
      •   靜態成員--包括函數和成員都必須在類外的某個地方進行定義:格式例如     類型+類名+::+變量名;    double Data::time=1;
        初始化靜態變量的時候,無論變量的限定詞是什麼,都是在類外進行初始化的,private也是如此
      •   靜態成員的存取:兩種狀況。
        第一種:沒有對象產生,直接調用。類名::變量名=值。這裏必須保證該靜態變量爲public
        第二種:有對象產生,也是直接調用。類名.變量名=值這裏必須保證該靜態變量爲public
      • (1)出如今類體外的函數不能指定關鍵字static;

        (2)靜態成員之間能夠互相訪問,包括靜態成員函數訪問靜態數據成員和訪問靜態成員函數;ios

        (3)非靜態成員函數能夠任意地訪問靜態成員函數和靜態數據成員;函數

        (4)靜態成員函數不能訪問非靜態成員函數和非靜態數據成員;優化

        (5)因爲沒有this指針的額外開銷,所以靜態成員函數與類的全局函數相比,速度上會有少量的增加;this

        (6)調用靜態成員函數,能夠用成員訪問操做符(.)和(->)爲一個類的對象或指向類對象的指調用靜態成員函數。

        url

    •   自引用
      •   每一個非靜態函數都知道他是爲了哪一個對象而調用的,所以能夠顯示的引用該對象。
        Date &Date::add_year(int n){
            if(d==29 && m==2 && ;leapyear(y+n)){
                d=1;
                m=3;
            }
            y+=n;
            return *this;
        }

        表達式中的 *this引用的就是找個函數的此次調用所針對的那個對象。大部分的this都是隱含的。對一個類中非靜態的成員的引用都要依靠隱式的使用this。格式:this->變量名。。spa

    •   可變的mutable--強制去掉const屬性
      •   若是在某個表示中只有一部分容許改變,將這些成員聲明爲mutable最合適了。
      •   若是一個對象在邏輯上表示爲const,可是它的大部分數據成員須要改變,那麼最好是將這些須要改變的數據成員放在另外一個獨立的對象中,簡接訪問。

    •   在類內部的函數定義
      •   一個函數若是在類的內部定義和聲明,應該是短小簡短額,就好像是在線(inline)的同樣。
        • 可是在類內部定義的函數有可能會引發一些沒必要要的疑慮,因此能夠用另外一種的方式進行。例如:把該函數在類外定義成inline函數。


    •   高效的定義數據類型
      •   例如在類中的一個構造函數中寫了一些判斷這個傳遞的參數是否合法的判斷語句。最好的方法是直接把這些代碼寫在該構造函數中,最好不要另外寫一個函數去包含這些語句。否則太麻煩
      •   增長一些協助函數
      •   重載一些運算符
    •   對象
      •   析構函數
        •   每當一個位於自由存儲的對象被刪除的時候,都會隱式的調用析構函數
      •   默認構造函數
        •   因爲const和引用必須進行初始化,因此含有這兩個類型的變量的類就不會有默認構造函數,因此必須本身定義默認構造函數。
        •   一個類若是定義了一個構造函數,就不會自動生成默認構造函數了,這個就必須本身定義默認構造函數了。(通常仍是寫上默認構造函數比較好)

      •   構造和析構
        •   局部變量:
          •   對於一個局部變量而言,每當控制走到該局部變量的聲明處,構造函數開始做用,當走出局部變量的做用域,析構函數開始做用,(以和構造函數構造順序相反的書序析構)
            例如 int a,b;構造a,b;析構b,a;
          • 賦值運算符和複製構造函數必須定義清楚,否則很容易形成內存泄漏,刪除不乾淨的問題。
            •   複製構造函數
              table ::table(const table & t){
                  p=new name(sz=t.sz);
                  for(int i=0;i<sz;i++)p[i]=t.p[i];
              }
              
              table &table::operator=(const table& t){
                  if(this!=&t){//小心自賦值  t=t;
                      delete [] p;
                      p=new Name[sz=t.sz];
                      for(int i=0;i<sz;i++)p[i]=t.p[i];
                  }
                  return *this;
              }



        • 成員初始化列表
          •   
            #include<iostream>
            #include<vector>
            #include<stdio.h>
            using namespace std;
            
            class club{
                string name;
                Table members;
                Table ooficers;
                Data founded;
                
                club(const string &n,Data fd);
            };
            club::club(const string &n,Data fd):name(n),members(),ooficers(),founded(fd){
            }

            對於沒有默認構造函數的類的成員變量,或者是cosnt,引用類型的成員變量,咱們都要使用成員列表初始化的方式最好,它可以提升效率設計

      • 局部靜態存儲
        • 例如
          void f(int i){
              static table tal;
              if(i){
                  static table tbl2;
              }
          }
          int main(){
              f(0);
              f(1);
              f(2);
          }
        • 靜態變量只會被構造一次,以後便不會再調用構造函數進行構造,析構的方式也是和構造的方式相反
    •   忠告



  • 運算符重載
    •   對於一元的運算符 @,@ a能夠解釋爲a.operator@(),或者是operator@(a).對於後綴的一元的運算符例如++,能夠表示爲a.operator@(int),或者operator@(a,int)
    •   一個運算符函數要麼是一個成員函數,要麼至少有一個用戶定義類型的參數。注意:若是某個運算符函數想要接受某個內部類型(常量或者是整數),那麼這個運算符函數確定不是成員函數。
      例如:加一個複數變量到一個整數a上面,a+2能夠寫成a.operator+(2),可是2+a寫成2.operator+()這個就不對了,違反了+法的規定。
      解決這個問題能夠把運算符函數定義成非成員函數,這樣就能夠十分輕鬆的解決這個問題。
      •   成員運算符和非成員運算符
        •   通常是隻在類自己中定義一些本質上就是須要修改第一個參數值得運算符,例如+=,-=之類的,它的第一個參數必定是變量且須要修改。而像+,-這樣的簡單的參數運算產生新值得通常就是放在類外進行定義的。
        •  
    •   當咱們遇到一些+法運算時,會出現各類各樣的數相加,這個就要咱們去設計不一樣的+運算符函數,這裏就必需要把加法運算符函數定義爲非成員函數
      •   
      •   上面的+=運算符中採用了優化的結構方式,經過減小了臨時變量來提升了效率,值的效仿。
    •   複製構造函數
      •   通常比較喜歡採用默認的複製構造函數。這個函數格式:X X(const X &);參數採用的是引用對象,而其餘的包含X對象的函數的參數都是採用值對象,不採用引用。
        X a=2;//這裏是先創建了X(2),而後去初始化了a
      •   做用:不管是本身寫的仍是默認的複製構造函數,都被用來初始化變量(如上),參數傳遞,值返回,以及異常處理上面。
    •   友元
      •   該函數能夠訪問類聲明的私有部分,friend聲明放在private或者public中都能訪問私有成員數據。
      •   最主要的是它能最爲兩個類的成員函數,從而很好的去實現兩個類對象之間的操做。
      • 一個類的成員也能夠是另外一個類的友元。
      • 友元函數的一些詳細做用
      • 2.友元函數的使用指針

        2.1友元函數的參數:code

        由於友元函數沒有this指針,則參數要有三種狀況:對象

        2.1.1 要訪問非static成員時,須要對象作參數;

        2.1.2 要訪問static成員或全局變量時,則不須要對象作參數;

        2.1.3 若是作參數的對象是全局對象,則不須要對象作參數;

        2.2友元函數的位置

        由於友元函數是類外的函數,因此它的聲明能夠放在類的私有段或公有段且沒有區別。

        2.3友元函數的調用

        能夠直接調用友元函數,不須要經過對象或指針

        2.4友元函數的分類:

        根據這個函數的來源不一樣,能夠分爲三種方法:

        2.4.1普通函數友元函數

        2.4.1.1目的:使普通函數可以訪問類的友元

        2.4.1.2語法:

        聲明: friend + 普通函數聲明

        實現位置:能夠在類外或類中

        實現代碼:與普通函數相同

        調用:相似普通函數,直接調用

        2.4.1.3代碼:

        class INTEGER

         {

          friend void Print(const INTEGER& obj);//聲明友元函數

         };

        void Print(const INTEGER& obj)

        {

           //函數體

        }

        void main()

        {

          INTEGER obj;

          Print(obj);//直接調用

        }

        2.4.2Y的全部成員函數都爲類X友元函數友元類

        2.4.2.1目的:使用單個聲明使Y類的全部函數成爲類X的友元,它提供一種類之間合做的一種方式,使類Y的對象能夠具備類X和類Y的功能。

        2.4.2.2語法:

        聲明位置:公有私有都可,常寫爲私有(把類當作一個變量)

        聲明: friend + 類名(不是對象哦)

        2.4.2.3代碼:

        class girl;

        class boy

        {

        public:

          void disp(girl &);

        };

        void boy::disp(girl &x) //函數disp()爲類boy的成員函數,也是類girl的友元函數

        {

          cout<<"girl's name is:"<<x.name<<",age:"<<x.age<<endl;//藉助友元,在boy的成員函數disp中,藉助girl的對象,直接訪問girl的私有變量

        }

        class girl

        {

        private:

          char *name;

          int age;

          friend boy; //聲明類boy是類girl的友元

        };

        main函數就不寫了和普通調用時同樣的。

        2.4.3Y的一個成員函數爲類X的友元函數

        2.4.3.1目的:使類Y的一個成員函數成爲類X的友元,具體而言:在類Y的這個成員函數中,藉助參數X,能夠直接以X的私有變量

        2.4.3.2語法:

        聲明位置:聲明在公有中 (自己爲函數)

        聲明:friend + 成員函數的聲明

        調用:先定義Y的對象y---使用y調用本身的成員函數---本身的成員函數中使用了友元機制

        2.4.3.3代碼:

        實現代碼和2.4.2.3中的實現及其類似只是設置友元的時候變爲friend void boy::disp(girl &);本身解決嘍……

        小結:其實一些操做符的重載實現也是要在類外實現的,那麼一般這樣的話,聲明爲類的友元是必須滴。

        4.友元函數和類的成員函數的區別

        4.1 成員函數有this指針,而友元函數沒有this指針。

        4.2 友元函數是不能被繼承的,就像父親的朋友未必是兒子的朋友。

    • 針對大型的對象
      •   大型對象的+法可能會屢次的調用複製構造函數,因此開銷會十分的大。爲了不過分的複製,咱們通常把對象的參數改成引用,這樣開銷會小弟

      • 這樣確實是減小了開銷。
    •   





  • 派生類
    •   派生類
      •   派生類中的基類與派生類的關係:若是drived有一個公共基類base,那麼必定能夠用drived* 對象給 base* 對象賦值,可是反過來不行,由於一個drived必定是一個base,可是反過來不必定(這裏必需要使用強制轉換)。
      •   用一個類作基類,這個類必須定義和聲明。
      •   派生類可使用基類中的public和protectd屬性的成員函數,可是派生類不能使用基類中的private屬性的成員。若是想訪問private成員,咱們能夠設置爲protectd屬性的,這樣除了派生類其餘的類和函數都沒法訪問
      •   構造函數和析構函數:
        派生類中的構造函數:基類中的構造函數的參數應該要在派生類構造函數的定義中有明確的描述。
        • 派生類的構造函數只能描述它本身的成員和本身直接基類的初始式,不能直接去初始化基類的成員

        • 派生類構造函數和析構順序:構造:基類-成員(按照成員聲明順序)-派生類,,析構:派生-成員(成員聲明的反順序)-基類。
      •   虛函數(多態性)
        •   在某一個虛函數的第一個聲明的那個類裏面,這個虛函數必須給它定義。(固然除了純虛函數之外)
        •   在派生類中若是沒必要用到這個虛函數的功能,咱們也是能夠不寫這個虛函數的。
        •   在派生類中使用虛函數能夠不用加上virturl這個關鍵字了。
        •   若是在派生類中存在一個和虛函數同名的、參數類型相同的函數,這個函數就會直接把虛函數的基類版本給覆蓋了。調用的時候咱們仍是必須加上做用域限定符::這樣才能調用咱們想要的版本
    •   抽象類
      •   若是一個類中有一個或者幾個純虛函數,這個類就是抽象類。其中不可以去建立一個抽象類對應的對象。
      •   抽象類只能做爲一個基類,最爲一個界面。不去實現任何細節。
    •   通常的類的層次的結構的設計
      •   首先定義一個抽象類。(沒有構造函數,定義一個虛析構函數,裏面的成員函數所有聲明爲純虛函數。)固然派生類是能夠實現多重繼承的。
      •   
相關文章
相關標籤/搜索