C++ 快速入門筆記:面向對象編程

類 & 對象

  1. 類定義

    class Box
    {
       public:
          double length;   // Length of a box
          double breadth;  // Breadth of a box
          double height;   // Height of a box
    };
    
  2. 對象定義

    Box Box1;          // 聲明 Box1,類型為 Box
    Box Box2;          // 聲明 Box2,類型為 Box
    
  3. 用 . 運算符訪問數據成員

類成員函數

  1. 在類的外部使用范圍解析運算符 :: 定義函數

    double Box::getVolume(void)
    {
        return length * breadth * height;
    }
    

類訪問修飾符

  1. public
    公有成員在程序中類的外部是可訪問的,可以不使用任何成員函數來設置和獲取公有變量的值。
  2. protected
    私有成員變量或函數在類的外部是不可訪問的,甚至是不可查看的,只有類和友元函數可以訪問私有成員。
  3. private
    保護成員變量或函數與私有成員十分相似,但有一點不同,保護成員在派生類(即子類)中是可訪問的。

構造函數 & 析構函數

  1. 類的構造函數是類的一種特殊的成員函數,它會在每次創建類的新對象時執行。構造函數的名稱與類的名稱是完全相同的,并且不會返回任何類型,也不會返回 void 。構造函數可用于為某些成員變量設置初始值。

  2. 使用初始化列表來初始化字段

    Line::Line( double len): length(len)
    {
        cout << "Object is being created, length = " << len << endl;
    }
    

    等價于

    Line::Line( double len)
    {
        cout << "Object is being created, length = " << len << endl;
        length = len;
    }
    
  3. 類的析構函數是類的一種特殊的成員函數,它會在每次刪除所創建的對象時執行。析構函數的名稱與類的名稱是完全相同的,只是在前面加了個波浪號(~)作為前綴,它不會返回任何值,也不能帶有任何參數。析構函數有助于在跳出程序(比如關閉文件、釋放內存等)前釋放資源。

拷貝構造函數

  1. 拷貝構造函數是一種特殊的構造函數,它在創建對象時,是使用同一類中之前創建的對象來初始化新創建的對象。拷貝構造函數通常用于:

    • 通過使用另一個同類型的對象來初始化新創建的對象。
    • 復制對象把它作為參數傳遞給函數。
    • 復制對象,并從函數返回這個對象。
  2. 如果類帶有指針變量,并有動態內存分配,則它必須有一個拷貝構造函數。

    Line::Line(const Line &obj)
    {
        cout << "Copy constructor allocating ptr." << endl;
        ptr = new int;
        *ptr = *obj.ptr; // copy the value
    }
    
    Line::~Line(void)
    {
        cout << "Freeing memory!" << endl;
        delete ptr;
    }
    

友元函數

  1. 類的友元函數是定義在類外部,但有權訪問類的所有私有(private)成員和保護(protected)成員。盡管友元函數的原型有在類的定義中出現過,但是友元函數并不是成員函數

  2. 友元可以是一個函數,該函數被稱為友元函數;友元也可以是一個類,該類被稱為友元類,在這種情況下,整個類及其所有成員都是友元。如果要聲明函數為一個類的友元,需要在類定義中該函數原型前使用關鍵字 friend 。

    #include <iostream>
    using namespace std;
    class Box
    {
        double width;
        public:
            friend void printWidth( Box box );
            void setWidth( double wid );
    };
    // 成員函數定義
    void Box::setWidth( double wid )
    {
        width = wid;
    }
    // 請注意:printWidth() 不是任何類的成員函數
    void printWidth( Box box )
    {
    /* 因為 printWidth() 是 Box 的友元,它可以直接訪問該類的任何成員 */
        cout << "Width of box : " << box.width <<endl;
    }
    // 程序的主函數
    int main( )
    {
        Box box;
    // 使用成員函數設置寬度
        box.setWidth(10.0);
    // 使用友元函數輸出寬度
        printWidth( box );
        return 0;
    }
    

內聯函數

  1. C++ 內聯函數是通常與類一起使用。如果一個函數是內聯的,那么在編譯時,編譯器會把該函數的代碼副本放置在每個調用該函數的地方。對內聯函數進行任何修改,都需要重新編譯函數的所有客戶端,因為編譯器需要重新更換一次所有的代碼,否則將會繼續使用舊的函數。
  2. 如果想把一個函數定義為內聯函數,則需要在函數名前面放置關鍵字 inline,在調用函數之前需要對函數進行定義。如果已定義的函數多于一行,編譯器會忽略 inline 限定符。在類定義中的定義的函數都是內聯函數,即使沒有使用 inline 說明符。

this 指針

  1. 在 C++ 中,每一個對象都能通過 this 指針來訪問自己的地址。this 指針是所有成員函數的隱含參數。因此,在成員函數內部,它可以用來指向調用對象。

指向類的指針

  1. 一個指向 C++ 類的指針與指向結構的指針類似,訪問指向類的指針的成員,需要使用成員訪問運算符 -> ,就像訪問指向結構的指針一樣。

類的靜態成員

  1. 我們可以使用 static 關鍵字來把類成員定義為靜態的。當我們聲明類的成員為靜態時,這意味著無論創建多少個類的對象,靜態成員都只有一個副本。
  2. 靜態成員在類的所有對象中是共享的。如果不存在其他的初始化語句,在創建第一個對象時,所有的靜態數據都會被初始化為零。我們不能把靜態成員放置在類的定義中,但是可以在類的外部通過使用范圍解析運算符 :: 來重新聲明靜態變量從而對它進行初始化。
  3. 靜態函數成員
    • 如果把函數成員聲明為靜態的,就可以把函數與類的任何特定對象獨立開來。靜態成員函數即使在類對象不存在的情況下也能被調用,靜態函數只要使用類名加范圍解析運算符 :: 就可以訪問。

繼承

  1. 基類 & 派生類
  • 一個類可以派生自多個類,這意味著,它可以從多個基類繼承數據和函數。定義一個派生類,我們使用一個類派生列表來指定基類。類派生列表以一個或多個基類命名,形式如下:

    class derived-class: access-specifier base-class
    

其中,訪問修飾符 access-specifier 是 public、protected 或 private 其中的一個,base-class 是之前定義過的某個類的名稱。如果未使用訪問修飾符 access-specifier,則默認為 private。

  1. 訪問控制和繼承

    • 派生類可以訪問基類中所有的非私有成員。因此基類成員如果不想被派生類的成員函數訪問,則應在基類中聲明為 private。
    • 我們可以根據訪問權限總結出不同的訪問類型,如下所示:(表格炸了)
    訪問 public protected private
    同一個類 yes yes yes
    派生類 yes yes no
    外部的類 yes no no
    • 一個派生類繼承了所有的基類方法,但下列情況除外:
      • 基類的構造函數、析構函數和拷貝函數。
      • 基類的重載運算符。
      • 基類的友元函數。
  2. 繼承類型

    • 當一個類派生自基類,該基類可以被繼承為 public、protected 或 private 幾種類型。繼承類型是通過上面講解的訪問修飾符 access-specifier 來指定的。
    • 幾乎不使用 protected 或 private 繼承,通常使用 public 繼承。當使用不同類型的繼承時,遵循以下幾個規則:
      • 公有繼承(public):當一個類派生自公有基類時,基類的公有成員也是派生類的公有成員,基類的保護成員也是派生類的保護成員,基類的私有成員不能直接被派生類訪問,但是可以通過調用基類的公有和保護成員來訪問。
      • 保護繼承(protected): 當一個類派生自保護基類時,基類的公有和保護成員將成為派生類的保護成員。
      • 私有繼承(private):當一個類派生自私有基類時,基類的公有和保護成員將成為派生類的私有成員。
  3. 多繼承

    class <派生類名>:<繼承方式1><基類名1>,<繼承方式2><基類名2>,…
    {
        <派生類類體>
    };
    

重載運算符和重載函數

  1. C++ 允許在同一作用域中的某個函數和運算符指定多個定義,分別稱為函數重載和運算符重載。
  2. 當調用一個重載函數或重載運算符時,編譯器通過把您所使用的參數類型與定義中的參數類型進行比較,決定選用最合適的定義。選擇最合適的重載函數或重載運算符的過程,稱為重載決策
  3. 函數重載
    • 在同一個作用域內,可以聲明幾個功能類似的同名函數,但是這些同名函數的形式參數(指參數的個數、類型或者順序)必須不同。
  4. 運算符重載
    • 重載的運算符是帶有特殊名稱的函數,函數名是由關鍵字 operator 和其后要重載的運算符符號構成的。與其他函數一樣,重載運算符有一個返回類型和一個參數列表。

      Box operator+(const Box& b)
      {
           Box box;
           box.length = this->length + b.length;
           box.breadth = this->breadth + b.breadth;
           box.height = this->height + b.height;
           return box;
      }
      
      

多態

  1. C++ 多態意味著調用成員函數時,會根據調用函數的對象的類型來執行不同的函數。

  2. 靜態鏈接 / 靜態多態 / 早綁定

  3. 虛函數

    • 虛函數 是在基類中使用關鍵字 virtual 聲明的函數。在派生類中重新定義基類中定義的虛函數時,會告訴編譯器不要靜態鏈接到該函數。

    • 我們想要的是在程序中任意點可以根據所調用的對象類型來選擇調用的函數,這種操作被稱為動態鏈接,或后期綁定

      class Shape {
      protected:
          int width, height;
      public:
            Shape( int a=0, int b=0)
            {
               width = a;
               height = b;
            }
            virtual int area()
            {
               cout << "Parent class area :" <<endl;
               return 0;
            }
      };
      
  4. 純虛函數

    • 可能想要在基類中定義虛函數,以便在派生類中重新定義該函數更好地適用于對象,但是您在基類中又不能對虛函數給出有意義的實現,這個時候就會用到純虛函數。

      class Shape {
      protected:
          int width, height;
      public:
            Shape( int a=0, int b=0)
            {
               width = a;
               height = b;
            }
          // pure virtual function
          virtual int area() = 0;
      };
      
    • = 0 告訴編譯器,函數沒有主體,上邊的虛函數是純虛函數。

數據抽象

  1. 數據抽象是指,只向外界提供關鍵信息,并隱藏其后臺的實現細節,即只表現必要的信息而不呈現細節。
  2. 訪問標簽強制抽象
    • 使用訪問標簽來定義類的抽象接口。一個類可以包含零個或多個訪問標簽
      • 使用公共標簽定義的成員都可以訪問該程序的所有部分。一個類型的數據抽象視圖是由它的公共成員來定義的。
      • 使用私有標簽定義的成員無法訪問到使用類的代碼。私有部分對使用類型的代碼隱藏了實現細節。

接口

  1. 接口描述了類的行為和功能,而不需要完成類的特定實現。
  2. 如果類中至少有一個函數被聲明為純虛函數,則這個類就是抽象類。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,534評論 1 51
  • 重新系統學習下C++;但是還是少了好多知識點;socket;unix;stl;boost等; C++ 教程 | 菜...
    kakukeme閱讀 20,022評論 0 50
  • C++ 面向對象編程 博客園地址:http://www.cnblogs.com/xiongxuanwen/p/42...
    先之閱讀 687評論 0 1
  • C++文件 例:從文件income. in中讀入收入直到文件結束,并將收入和稅金輸出到文件tax. out。 檢查...
    SeanC52111閱讀 2,847評論 0 3
  • 前言 人生苦多,快來 Kotlin ,快速學習Kotlin! 什么是Kotlin? Kotlin 是種靜態類型編程...
    任半生囂狂閱讀 26,276評論 9 118