<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      編程成長之路

      我們都是站在父母的肩上去看他們不曾看到的風景!加油!
        博客園  :: 首頁  :: 新隨筆  :: 聯系 :: 訂閱 訂閱  :: 管理

      C++基礎學習筆記

      Posted on 2023-05-16 14:03  來顆維C  閱讀(80)  評論(0)    收藏  舉報

      變量

      • 變量的作用

        方便我們管理內存空間
        
      • 變量使用語法

        數據類型  變量名 = 變量初始值;
        示例:
        int a = 10;
        
        cout << "a = " << a << endl;
        

        釋義:創建變量 a ,輸出內容為變量 a 的值。

      常量

      • 常量的作用

        用于記錄程序中不可更改的數據
        
      • define 宏常量使用語法

        #define 常量名 常量值
        
        宏常量通常定義在最上方
        

        釋義:#define 通常在文件上方定義,表示一個常量

      • const 修飾的常量使用語法

        const 數據類型 常量名 = 常量值
        
        修飾變量位置可在最上方也可在調用處上方
        

        釋義:const通常在變量定義前加關鍵字const,修飾該變量為常量,不可修改

      • 示例:

        #define Day 365
        
        const int month = 12;
        

      關鍵字

      • 不要用關鍵字給變量或常量起名稱,否則會產生歧義。
      asm auto bool break case catch char
      class const const_cast continue default delete do
      double dynamic_cast else enum explicit export extern
      false float for friend goto if inline
      int long mutable namespace new operator private
      protected public register reinterpret_cast return short signed
      sizeof static static_cast struct switch template this
      throw true try typedef typeid typename union
      unsigned using virtual void volatile wchar_t while

      標識符命名規則

      • 標識符作用:給變量、常量命名
        • 標識符不能是關鍵字
        • 標識符只能由字母、數字、下劃線組成
        • 第一個字符必須為字母或下劃線
        • 標識符中字母區分大小寫

      數據類型

      C++規定在創建一個變量或常量時,必須要指定出相應的數據類型,否則無法給變量分配內存。

      數據類型-整型

      • 整型變量表示的是整數類型的數據
      • C++中能夠表示整型的類型有以下幾種方式,區別在于所占內存空間不同:
      數據類型 占用空間 取值范圍
      short(短整數) 2字節 (-2^15 ~2^15-1)
      int(整型) 4字節 (-2^31 ~2^31-1)
      long(長整型) Windows為4字節,Linux為4字節(32位),8字節(64位) (-2^31 ~2^31-1)
      long long (長長整型) 8字節 (-2^63 ~2^63-1)

      數據類型sizeof關鍵字

      • 作用:利用sizeof關鍵字可以統計數據類型所占內存大小

      • 語法

        sizeof(數據類型 / 變量)
        
      • 示例:

        int main() {
          short a = 10;
          int b =11;
          long c = 12;
          long long d = 13;
          cout << "short 類型所占內存空間為:" << sizeof(short) << endl;
          cout << "int 類型所占內存空間為:" << sizeof(int) << endl;
          cout << "long 類型所占內存空間為:" << sizeof(long) << endl;
          cout << "long long 類型所占內存空間為:" << sizeof(long long) << endl;
          system("pause");
          system("cls");   //清屏操作
          return 0;
        }
        

      數據類型-實型

      • 作用:用于表示小數
      • 浮點型變量分為兩種:
        • 單精度 float
        • 雙精度 double
        • 兩者區別在于表示的有效數字范圍不同
      數據類型 占用空間 有效數字范圍
      float 4字節 7位有效數字
      double 8字節 15~16位有效數字
      • 默認情況下,輸出一個小數,會顯示出6位有效數字

      • float 類型的變量后一般加一個 f ,否則float的數據類型默認識別為double雙精度。

      • 示例:

        int main() {
        float f1 = 3.1415926f;
        double f2 =3.1415926;
        cout << "f1 = " << f1 << endl;
        cout << "f2 = " << f2<< endl;
        
        //科學計數法
        float f3 = 3e2;    //3 * 10^2;
        float f4 = 3e-2;  //3 * 0.1^2;
        // e 后面如果是正數,則代表乘以100^n;
        // e 后面如果是負數,則代表乘以0.1^n;
        
        system("pause");
        return 0;
        }
        

      數據類型-字符型

      • 作用:字符型變量用于顯示單個字符

      • 語法:

        char ch = 'a';
        

        注意1:在顯示字符型變量時,用單引號將字符括起來,不要用雙引號
        注意2:單引號內只能有一個字符,不可以用字符串

      • C和C++中字符型變量只占用一個字節

      • 字符型變量并不是把字符本身放到內存中存儲,而是將對應的ASCII編碼放入到存儲單元

      • 示例

        int main() {
            char ch1 = 'a';
            char ch2 = 'A';
        
            cout << ch1 << endl;
            cout << (int)ch2 << endl;    //釋義1
        system("pause");
        return 0;
        }
        

        釋義1:輸出 char 被強制轉化成 int 類型的語句。就是輸出 A 的ASCII編碼 ‘65’

      • ASCII碼大致由以下兩部分組成:

        • ASCII非打印控制字符:ASCII表上的數字 0-31 分配給了控制字符,用于控制打印機等一些外圍設備
        • ASCII打印字符:數字 32-126 分配給了能在鍵盤上找到的字符,當查看或打印文檔時就會出現。

      數據類型-轉義字符

      • 作用:用于表示一些不能顯示出來的ASCII字符,例如常用的有:\n \ \t

      數據類型-字符串型

      • 作用:用于表示一串字符

      • 注意:字符串值需要用雙引號 "" 包含起來,與字符使用的單引號 '' 做區分。

      • C風格字符串:char 變量名[] = "字符串值";
        示例:

        int main() {
          char str1[] = "hello-world";   //C風格字符串需要在變量名后面加中括號 []
          cout << str1 << endl;
          system("pause");
          return 0;
        }
        
      • C++風格字符串:string 變量名 = "字符串值";
        示例:

        #include<string>   //用C++風格字符串時候,要引用這個頭文件
        int main() {
          string str2 = "hello-world";
          cout << str2 << endl;
          system("pause");
          return 0;
        }
        

      布爾類型bool

      • 作用:布爾數據類型代表真或假的值

      • bool類型只有兩個值

        • true --- 真(本質是1)
        • false --- 假(本質是0)
      • bool類型占1個字節大小

      • 示例:

        int main() {
          bool flag = true;
          cout << flag << endl;   
        
          flag = false;           //重新賦值
          cout << flag << endl;
        
          cout << "size of bool =" << sizeof(bool) << endl;
        
          system("pause");
          return 0;
        }
        

      數據的輸入

      • 作用:用于從鍵盤獲取數據

      • 關鍵字:cin

      • 語法

        cin >> 變量;
        
      • 示例:

        int main() {
          int a = 0;
          cout << "請輸入整型變量:" << endl;
          cin >> a;
          cout << a << endl;
        
          double d =0;
          cout << "請輸入浮點型變量:" << endl;
          cin >> d;
          cout << d << endl;
        
          char ch =0;
          cout << "請輸入字符型變量:" << endl;
          cin >> ch;
          cout << ch << endl;
        
          system("pause");
          return 0;
        }
        

      運算符

      作用:用于執行代碼的運算

      運算符類型 作用
      算數運算符 用于處理四則運算
      賦值運算符 用于將表達式的賦值給變量
      比較運算符 用于表達式的比較,并返回一個真值或假值
      邏輯運算符 用于根據表達式的值返回真值或假值

      算數運算符

      作用:用于處理四則運算

      運算符 術語 示例 結果
      + 正號 +3 3
      - 負號 -3 -3
      + 10+5 15
      - 10-5 5
      * 10*5 50
      / 10/5 2
      % 取模(取余) 10%3 1
      ++ 前置遞增 a=2;b=++a; a=3;b=3
      ++ 后置遞增 a=2;b=a++; a=3;b=2
      -- 前置遞減 a=2;b=--a; a=1;b=1;
      -- 后置遞減 a=2;b=a--; a=1,b=2;
      • 示例:

        int main() {
          //加減乘除
          int a1 = 10;
          int b1 = 3;
        
          cout << a1 + b1 << endl;
          cout << a1 - b1 << endl;
          cout << a1 * b1 << endl;
          cout << a1 / b1 << endl;  //兩個整數相除,結果依然是整數,將小數部分去除
        
          int a3 = 10;
          int b3 = 20;
          cout << a3 / b3 << endl;  //結果為0
        
          int a2 = 10;
          int b2 = 0;
          cout << a2 / b2 << endl;  //錯誤!兩個數相除,除數是不可以為0的
        
          //兩個小數可以相除
          double d1 = 0.5;
          double d2 = 0.25;
          cout << d1 / d2 << endl;  //運算的結果也可以是小數
          
          //取模運算本質就是求余數
          int a4 = 10;
          int b4 = 3;
          cout << a4 % b4 << endl;  //取余為1
        
          int a5 = 10;
          int b5 = 20;
          cout << a5 % b5 << endl;  //取余為10,當被除的數沒有除數大時,取余的值為被除的數值。取模運算的除數不可為0;
        
          //兩個小數時不可以做取模運算的
        
          //前置與后置的區別
          //前置遞增是先讓變量+1然后進行表達式運算
          int a6 = 10;
          int b6 = ++a6 * 10;
          cout << a6 << endl;  //輸出為11
          cout << b6 << endl;  //輸出為110
        
          //后置遞增是先進行表達式運算后讓變量+1
          int a7 = 10;
          int b7 = a7++ * 10;
          cout << a7 << endl;  //輸出為11
          cout << b7 << endl;  //輸出為100
        
          //前置遞減是先讓變量-1然后進行表達式運算
          int a8 = 10;
          int b8 = --a8 * 10;
          cout << a8 << endl;  //輸出為9
          cout << b8 << endl;  //輸出為90
        
          //后置遞減是先進行表達式運算后讓變量-1
          int a9 = 10;
          int b9 = a9-- * 10;
          cout << a9 << endl;  //輸出為9
          cout << b9 << endl;  //輸出為100
        
          system("pause");
          return 0;
        }
        

      賦值運算符

      作用:用于將表達式的值賦給變量

      運算符 術語 示例 結果
      = 賦值 a=2;b=3; a=2;b=3;
      += 加等于 a=0;a+=2; a=2;
      -= 減等于 a=5;a-=3; a=2;
      * = 乘等于 a=2;a*=2; a=4;
      /= 除等于 a=4;a/=2; a=2;
      %= 模等于 a=3;a%=2; a=1;
      • 示例:

        int main() {
          //加等于 +=
          int a = 10;
          a += 2;             //a = a + 2
          cout << a << endl;  //輸出為12
        
          //減等于 -=
          a = 10;
          a -= 2;             //a = a - 2
          cout << a << endl;  //輸出為8
        
          //乘等于 *=
          a = 10;
          a *= 2;             //a = a * 2
          cout << a << endl;  //輸出為20
        
          //除等于 /=
          a = 10;
          a /= 2;             //a = a / 2
          cout << a << endl;  //輸出為5
        
          //模等于 %=
          a = 10;
          a %= 2;             //a = a % 2
          cout << a << endl;  //輸出為0
        
          system("pause");
          return 0;
        
        }
        

      比較運算符

      作用:用于表達式的比較,并返回一個真值(1)或假值(0)

      運算符 術語 示例 結果
      == 相等于 4==3 0
      != 不等于 4!=3 1
      < 小于 4<3 0
      > 大于 4>3 1
      <= 小于等于 4<=3 0
      >= 大于等于 4>=1 1
      • 示例

        int main() {
        
          //比較運算符
          int a = 10;
          int b = 20;
        
          // ==
          cout << (a == b) << endl;  //輸出0,值為假
        
          // !=
          cout << (a != b) << endl;  //輸出1,值為真
        
          // >
          cout << (a > b) << endl;   //輸出0,值為假
        
          // <
          cout << (a < b) << endl;   //輸出1,值為真
        
          // <=
          cout << (a <= b) << endl;  //輸出1,值為真
        
          // >=
          cout << (a >= b) << endl;  //輸出0,值為假
        
          system("pause");
          return 0;
        }
        

      邏輯運算符

      • 作用:用于根據表達式的值換貨真值或假值
      • 運算符號
      運算符 術語 示例 結果
      !a 如果a為假,則!a為真;如果a為真,則!a為假
      && a&&b 如果a和b都為真,則結果為真,否則為假
      || a||b 如果a和b有一個為真,則結果為真,二者都為假時,結果為假
      • 示例

        int main() {
          int a = 10;
        
          //在C++中值除了0都為真
          //非運算,真變假,假變真
          //邏輯運算符  非  !
          cout << !a << endl;    //輸出為0,值為假。非真即為假
          cout << !!a << endl;    //輸出為1,值為真。非假即為真
        
          //同真為真,其余為假
          //邏輯運算符 與   &&
          int b = 10;
          cout << (a && b) << endl;   //輸出為1,值為真。
          int a = 0;
          cout << (a && b) << endl;   //輸出為0.值為假。
          int b = 0;
          cout << (a && b)  << endl;  //輸出為0,值為假,因為變量的值為0時都為假。
        
          //同假為假,其余為真
          //邏輯運算符 或   ||  
          int a = 10;
          int b = 10; 
          cout << (a || b) << endl;   //輸出為1,值為真。
          int a = 0;
          cout << (a || b) << endl;   //輸出為1,值為真。
          int b = 0;
          cout << (a || b) << endl;   //輸出為0,值為假。
        
          system("pause");
          return 0;
        
        }
        

      程序流程結構

      C/C++支持最基本的三種程序運行結構:順序結構、選擇結構、循環結構

      • 順序結構:程序按順序執行,不發生跳轉

      選擇結構

      if 語句

      作用:依據條件是否滿足,有選擇的執行相應功能,執行滿足條件的語句
      if 語句的三種形式

      • 單行格式 if 語句
        語法:if (條件) {條件滿足執行的語句}
        插入圖片
        示例:

        int main() {
          //選擇結構單行 if 語句
          //用戶輸入分數,如果分數大于600,視為考上一本大學,在屏幕上輸出
        
          //用戶輸入分數
          int score = 0;
          cout << "請輸入分數:" << endl;
          cin >> score;                    //把輸入的值賦值到 score 中
        
          //打印用戶輸入的分數
          cout << "您輸入的分數:" << score << endl;
        
          //判斷分數是否大于600,如果大于,那么輸出
          // if 條件后面不要加分號 ; 
          if (score > 600) {                         //判斷score值是否大于600
            cout << "恭喜您考上了一本大學" << endl;
          }
        
          system("pause");
          return 0;
        }
        
      • 多行格式 if 語句
        語法: if (條件) {條件滿足執行的語句}else{條件不滿足執行的語句}
        單行格式if語法
        示例:

        int main() {
          //選擇結構  多行 if 語句
          //輸入考試分數,如果分數大于等于600,判斷考上一本,輸出考上一本
          //如果輸入分數低于600,則輸出未考上一本
        
          //輸入分數
          int score = 0;
          cout << "請輸入考試分數:" << endl;
          cin >> score;
        
          //輸出用戶輸入的分數
          cout << "您輸入的分數為:" << score << endl;
        
          //判斷是否滿足條件
          if ( score >= 600 ) {                   //判斷score是否大于等于600
            cout << "恭喜考上了一本大學" << endl;  //當score大于等于600時,值為真,則輸入此語句
          }
          else {
            cout << "未考上一本大學" << endl;      //當score小于600時,值為假,則輸出此語句
          }
        
          system("pause");
          return 0;
        }
        
      • 多條件的 if 語句
        語法:if (條件1) {條件1滿足執行的語句}else if (條件2) {條件2滿足執行的語句}.......else {條件都不滿足時執行的語句}
        多行if語句
        示例:

        int main() {
          //選擇結構 多條件 if 語句
          //輸入一個分數,如果大于600分,判斷考上一本,如果大于等于500分,判斷考上二本,如果大于等于400分,則判斷考上三本.....如果上述條件都不滿足,則判斷沒考上本科
        
          //用戶輸入分數
          int score = 0;
          cout << "請輸入分數:" << endl;
          cin >> score;
        
          //提示用戶輸入的分數
          cout << "您輸入的分數為:" << score << endl;
        
          //判斷
          if (score > 600) {                      //判斷score是否大于600
            cout << "您考上了一本" << endl;        //大于600時,值為真,則輸出此語句
          }
          else if (score > 500) {                 //判斷score是否大于500
            cout << "您考上了二本" << endl;        //大于500時,值為真,則輸出此語句
          }
          else if (score > 400) {                 //判斷score是否大于400
            cout << "您考上了三本" << endl;        //大于400時,值為真,則輸出此語句
          }
          else {                                  //條件都不滿足時
            cout << "您沒考上本科" << endl;        //輸出此語句
          }
        
          system("pause");
          return 0;
        }
        
      • 嵌套 if 語句
        用處:在 if 語句中,可以嵌套使用 if 語句,達到更精確的條件判斷
        多條件if語句
        示例要求:

        • 提示用戶輸入一個分數,根據分數做如下判斷
        • 分數如果大于600分視為考上一本,大于500分考上二本,大于400分考上三本,其余視為沒考上本科
        • 在一本分數中,如果大于700分視考入北大,大于650分視考上清華,大于600分考入人大

        示例:

        int main() {
        
          int score = 0;
        
          //提示輸入分數
          cout << "請輸入考試分數" << endl;
          cin >> score;
        
          //顯示高考分數
          cout << "您輸入的分數為:" << score << endl;
        
          //判斷
          //大于600分
          if (score > 600) {
            cout << "您考上了一本。" << endl;
            //大于700分
            if (score > 700) {
              cout << "您考上北大。" << endl;
            }
            //大于650分
            else if (score > 650) {
              cout << "您考上清華。" << endl;
            }
            //未滿足條件時
            else {
              cout << "您考上人大。" << endl;
            }
          }
          //大于500分
          else if (score > 500) {
            cout << "您考上了二本。" << endl;
          }
          //大于400分
          else if (score > 400) {
            cout << "您考上了三本。" << endl;
          }
          //條件都不滿足時
          else {
            cout << "您未考上本科。" << endl;
          }
        
          system("pause");
          return 0;
        }
        
      • 游戲段位排名劃分
        要求:

        • 按照300分為大師、260分為鉑金、220分為鉆石、180分為黃金劃分
        • 超過320分為王者、超過360分為最強王者、超過400分宇宙韓國
          示例:
        int main() {
          int score = 0;
          cout << "請輸入您的排位得分:" << endl;
          if (score > 300) {
            cout << "您的段位已到大師級別" >>
            if (score > 320) {
              cout << "您的世界排名已到王者" << endl;
            }
            else if (score > 360){
              cout << "您的世界排名已到最強王者" << endl;
             }
             else if (score > 400) {
              cout << "您的世界排名已到宇宙韓國" << endl;
             }
             else {
              cout << "抱歉,您的分數還沒到世界排名,僅僅是大師級別" << endl;
             }
          }
          else if (score > 260) {
            cout << "您的段位已到鉑金級別" << endl;
          }
          else if (score > 220) {
            cout << "您的段位已到鉆石級別" << endl;
          }
          else if (score > 180) {
            cout << "您的段位已到黃金級別" << endl;
          }
          else {
            cout << "抱歉,您的排位得分還未達到黃金段位" << endl;
          }
        
          system("pause");
          return 0;
        }
        

      三目運算符

      作用:通過三目運算符實現簡單的判斷
      語法:表達式1 ? 表達式2 : 表達式3

      • 釋義:

        如果表達式1的值為真,執行表達式2,并返回表達式2的結果;
        如果表達式1的值為假,執行表達式3,并返回表達式3的結果;
        

        示例:

        int main() {
        
          int a = 10;
          int b = 20;
          int c = 0;
        
          c = (a > b ? a : b);         //a > b 的值為假,執行表達式 b ,并且為 c 賦值
          cout << "c =" << c << endl;  
        
          //在C++中三目運算符返回的是變量,可以繼續賦值
          (a > b ? a : b) = 100;       //a > b 的值為假,執行表達式b,并且為 b 賦值
          cout << "a = " << a << endl;  //輸出10
          cout << "b = " << b << endl;  //輸出100
        
          (a < b ? a : b) = 100;       //a < b 的值為真,執行表達式a,并且為 a 賦值
          cout << "a = " << a << endl;  //輸出100
          cout << "b = " << b << endl;  //輸出20
        
          system("pause");
          return 0;
        }
        

      switch語句

      作用:執行多條件分支語句;

      • 語法:

        switch(表達式) {
          case 結果1:執行語句;
          break;
        
          case 結果2:執行語句;
          break;
        
          ......
        
          default:執行語句;
          break;
        }
        

        示例:

        int main() {
        //給電影打分
        //10~9 經典
        //8~7 非常好
        //6~5 一般
        //5以下 爛片
        
        //提示用戶給電影打分
        cout << "請給電影進行打分" << endl;
        
        //用戶開始進行打分
        int score = 0;
        cin >> score;
        cout << "您打的分數為:" << score << endl;
        
        //根據用戶輸入的分數來提示用戶最后的結果
        switch (score) {
          case 10:
              cout << "您認為是經典電影" << endl;
              break;
          case 9:
              cout << "您認為是經典電影" << endl;
              break;
          case 8:
              cout << "您認為是非常好的電影" << endl;
              break;
          case 7:
              cout << "您認為是非常好的電影" << endl;
              break;
          case 6:
              cout << "您認為是一般的電影" << endl;
              break;
          case 5:
              cout << "您認為是一般的電影" << endl;
              break;
          default :
              cout << "您認為是爛片" << endl;
              break;
          }
        }
        

        if 語句與 switch 區別:

        switch 缺點:判斷時候只能是整型或者字符型,不可以判斷一個區間(指定值)
        switch 優點:結構清晰,執行效率高
        注意:case里如果沒有break,那么程序會一直向下執行
        

      循環結構

      while 循環語句

      作用:滿足循環條件,執行循環語句
      語法:while(循環條件){循環語句}
      釋義:只要循環條件的結果為真,就執行循環語句
      插入圖片

      • 示例:

        int main() {
        
          //從0開始循環輸出到9
          //注意事項:在寫循環一定要避免死循環
          //在執行循環語句的時候,程序必須提供跳出循環的出口,否則出現死循環
          int num = 0;
        
          //while ()中填入循環條件
          while (num < 10 ) {
            cout << num << endl;
            num++;
          }
        
          system("pause");
          return 0;
        
        }
        

        案例:猜數字游戲
        要求:系統隨機生成一個1-100之間的數字,玩家進行猜測,如果猜錯提示玩家數字過大或過小,如果猜對了提示玩家勝利,并且退出游戲。
        插入圖片
        代碼:

        int main() {
        
          //添加隨機數種子,利用當前時間系統生成隨機數,防止每次隨機數都一樣
          srand ( (unsigned int)time(null) );
          //系統生成隨機數
          int num = rand()%100+1;     //生成0~99的隨機數,+1是指代1-100;
          
          //玩家進行猜測
          int val = 0;
          cout << "請玩家輸入猜測的數字:" << endl;
        
          while (1) {
          cin >> val;
          //判斷猜測
          if ( val > num) {             //猜錯提示過大,重新返回玩家進行猜測
            cout << "猜測過大" << endl;
          }
          else if (val < num ) {         //猜錯提示過小,重新返回玩家進行猜測
            cout << "猜測過小" << endl;
          }
          else {                             //猜對  退出游戲   
            cout << "恭喜你猜對了" << endl;
          }
          }
          system("pause");
          return 0;
          
        }
        

      do...while 循環語句

      作用:滿足循環條件,執行循環語句
      語法: do{循環語句} while(循環條件);
      注意:與while的區別在于do...while會先執行一次循環語句,再判斷循環條件
      插入圖片

      • 示例:

        int main() {
          //在屏幕中輸出0-9這十個數字
        
          int num = 0;
        
          do {                     //先輸出循環語句
            cout << num << endl;     
            num++;                 
          }while (num < 10);       //判斷循環條件
        
          system("pause");
          return 0;
        }
        

        練習案例:水仙花數
        案例描述:水仙花數是指一個3位數,他的每個位上的數字的3次冪之和等于它本身
        例如:13+53+3^3=153
        請利用 do...while語句,求出所有3位數中的水仙花數

        #include(math.h)
        int main() {
        
          int sum  = 100;
          do {
            int a = 0;
            int b = 0;
            int c = 0;
            a = sum / 100;
            b = sum / 10 % 10;
            c = sum % 10;
        
            if (a*a*a + b*b*b + c*c*c == sum) {
              cout << num << endl;
            }
            num++;
          } while (sum < 1000);                   //別忘記加分號 ; 
          system("pause");
          return 0;
        }
        

      for 循環

      作用:滿足循環條件,執行循環語句
      語法: for(起始表達式;條件表達式;末尾循環體){循環語句;}

      • 示例:

        int main(){
          for (int i = 0; i < 10; i++){
            cout << i << endl;
          }
        
          system("pause");
          return 0;
        }
        

        詳解:

        using namespace std;
        
        int main(){
          //for 循環
          //從數字0打印到數字9
          for (int i = 0; i < 10; i++){
            cout << i << endl;
          }
          system("pause");
          return 0;
        }
        

        練習案例:敲桌子
        要求:從1開始數到數字100,如果數字個位含有7或者數字十位含有7,再者該數字是7的倍數,我們打印敲桌子,其余數字直接打印輸出。

        using namespace std;
        int main(){
          //先輸出1~100數字
          for (int num = 1;num < 101; num++){
            //從100個數字中找出特殊數字,打印敲桌子
            //如果是7的倍數、個位有7、十位有7,視為特殊數字
            if (num % 7 == 0 || num / 10 == 7 || num / 10 == 7  ) {
              cout << "特殊數字:" << num << " 敲桌子" << endl;
            }
            else {
              cout << num << endl;
            }
          }
          system("pause");
          return 0;
        }
        

      循環嵌套

      作用:在循環體內再嵌套一層循環,解決矩陣式的實際問題

      • 示例:

        using namespace std;
        int main(){
        
          for (int i = 0; i < 11; i++){
            for (int j = 0; j < 11; j++){
              cout << "* " ;
            }
          }
        
          system("pause");
          return 0;
        }
        

        案例:乘法口訣表
        示例:

        using namespace std;
        int main(){
          
          for (int i = 1; i < 10; I++){
            for (int j = 1; j <= i; j++){
              cout << i << "*" << j << "=" << i*j << "  ";
            }
            cout << endl;
          }
          system("pause");
          return 0;
        }
        

      跳轉語句

      break 語句

      作用:用于跳出選擇結構或者循環結構
      break 使用的地方:

      • 出現在switch條件語句中,作用是終止 case 并跳出 switch

      • 出現在循環語句中,作用是跳出當前的循環語句

      • 出現在嵌套循環中,跳出最近的內層循環語句

      • 示例:

        using namespace std;
        int main(){
          //出現在 switch 語句中
          cout << "請選擇副本難度" << endl;
          cout << "1、普通" << endl;
          cout << "2、中等" << endl;
          cout << "3、困難" << endl;
        
          int select = 0;  //選擇難度結果的變量
          cin >> select;   //等待用戶輸入
        
          switch (select){
            case 1:
               cout << "您選擇的是普通難度" << endl;
               break;
            case 2:
               cout << "您選擇的是中等難度" << endl;
               break;
            case 3:
               cout << "您選擇的是困難模式" << endl;
               break;
            default :
               break;
          }
          //出現在循環語句中
          //出現在嵌套循環語句中
          system("pause");
          return 0;
        }
        

      continue 語句

      作用:在循環語句中,跳過本次循環中余下尚未執行的語句,繼續執行下一次循環

      • 示例:

        using namespace std;
        int main(){
          for (int i = 0; i <= 100; i++){
            //如果是奇數輸出,偶數不輸出
            if (i % 2 == 0){     //篩選條件,執行到此就不再向下執行,執行下一次循環
              continue;   //break會退出循環,而continue不會
            }
          }
          system("pause");
          return 0;
        }
        

      goto 語句

      作用:可以無條件跳轉語句
      語法:goto 標記;
      釋義:如果標記的名稱存在,執行到goto語句時,會跳轉到標記的位置

      • 示例:

        using namespace std;
        int main(){
          cout << "1" << endl;
          cout << "2" << endl;
          goto FLAG;               //跳轉到標記
        
          cout << "3" << endl;
          cout << "4" << endl;
        
          FLAG:                    //標記
          cout << "5" << endl;
        
          system("pause");
          return 0;
        }
        

      數組

      概述:數組時一個集合,里面存放了相同類型的數據元素
      特點:

      • 數組中的每個數據元素都是相同的數據類型
      • 數組是由連續的內存位置組成的

      一維數組

      一維數組定義方式

      一維數組定義的三種方式:

      • 數據類型 數組名[數組長度];

      • 數據類型 數組名[數組長度] = {值1,值2,...};

      • 數據類型 數組名[] = {值1,值2,...};

      • 示例:

        using namespace std;
        int main(){
          //數據類型 數組名[數組長度];
          int arr[5];
          //給數組中的元素進行賦值
          //數組元素的下標時從0開始索引的
          arr[0] = 10;
          arr[0] = 20;
          arr[0] = 30;
          arr[0] = 40;
          arr[0] = 50;
          //訪問數據元素
          cout << arr[0] << endl;
        
          //數據類型 數組名[數組長度] = {值1,值2,...};
          //如果在初始化數據的時候,沒有全部填寫完,會用0填補剩余數據
          int arr2[5] = {100,200,300};
          //利用循環輸出數組中的元素
          for (int i = 0; i < 5; i++){
            cout << arr2[i] << endl;
          }
        
          //數據類型 數組名[] = {值1,值2,...};
          //定義數組的時候,必須有初始的長度
          int arr3[] = {90,80,70,60,50,40,30,20,10};
          for (int j = 0; j < 9; j++){
            cout << arr3[j] << endl;
          }
        
          system("pause");
          return 0;
        }
        

        注意1:數組名的命名規范與變量名命名規范一致,不要和變量重名
        注意2:數組中下標是從0開始索引

      一維數組數組名

      一維數組名稱的用途:

      • 可以統計整個數組在內存中的長度

        sizeof(arr)
        sizeof(arr[0])
        
      • 可以獲取數組在內存中的首地址

        cout << arr << endl;
        
      • 示例:

        using namespace std;
        int main(){
        
          //可以統計整個數組在內存中的長度
          int arr[10] = {1,2,3,4,5,6,7,8,9,10};
          cout << "整個數組占用內存空間為:" << sizeof(arr) << endl;
          cout << "每個元素占用內存空間:" << sizeof(arr[0]) << endl;
          cout << "數組中元素個數為:" << sizeof(arr) / sizeof(arr[0]) << endl;
        
          //可以獲取數組在內存中的首地址
          cout << "數組首地址為:" << arr << endl;    //輸出十六進制的內存地址
          cout << "數組首地址為:" << (int)arr << endl; //輸出十進制的內存地址
          cout << "數組中第一個元素地址為:" << (int)&arr[0] << endl; 
        
          //數組名是常量,不可以進行賦值操作
        
          system("pause");
          return 0;
        }
        

        案例:五只小豬稱重
        要求:在一個數組中記錄五只小豬的體重,找出并打印最重的小豬體重。

        using namespace std;
        int main(){
        
          //創建五只小豬體重的數組
          int arr[5] = {300,350,200,400,250};
        
          //從數組中找到最大值
          int max = 0;    //先認定一個最大值為0
        
          for (int i = 0; i < 5; i++){
            //如果訪問的數組中的元素比 max 的值還要大,更新 max 值
            if (arr[i] > max){
              max = arr[i]; 
            }
          }
        
          //打印最大值
          cout << "最重的小豬體重為:" << max << endl;
        
          system("pause");
          return 0;
        }
        

        案例2:數組元素逆置
        要求:請聲明一個5元素的數組,并且將元素逆置

        using namespace std;
        int main(){
        
          //實現數組元素逆置
          //創建數組
          int arr[5] = {1,3,2,5,4};
          cout << "數組逆置前:" << endl;
          for (int i = 0; i <5; i++){
            cout << arr[i] << endl;
          }
        
          //實現逆置
          //記錄起始下標位置
          int start = 0;
        
          //記錄結束下標位置
          int end = sizeof(arr)/sizeof(arr[0]) - 1; //末尾元素下標
        
          while (start < end) {
        
          //起始下標與結束下標的元素互換
          int temp = arr[start];
          arr[start] = arr[end];
          arr[end] = temp;
        
          //起始位置++,結束位置--。下標更新
          start++;
          end--;
          }
          //循環執行操作,直到起止位置 >= 結束位置
          cout << "數組逆置后:" << endl;
          for (int i = 0; i <5; i++){
            cout << arr[i] << endl;
          }
        
          system("pause");
          return 0;
        }
        

      冒泡排序

      作用:最常用的排序算法,對數組內元素進行排序

      • 比較相鄰的元素,如果第一個比第二個大,就交換他們兩個

      • 對每一堆相鄰元素做同樣的工作,執行完畢后,找到第一個最大值

      • 重復上述步驟,每次比較次數-1,直到不需要比較

      • 示例:

        using namespace std;
        int main(){
        
          //利用冒泡排序實現升序序列
          int arr[9] = {4,2,8,0,5,7,1,3,9};
          cout << "排序前:" << endl;
          for (int i = 0; i < 9; i++){
            cout << arr[i] << " " ;
          }
          cout << endl;
        
          //開始冒泡排序
          //總共排序輪數為元素個數 -1 
          for (int i = 0; i < (sizeof(arr)/sizeof(arr[0]) - 1); i++){
            //內層循環對比,次數 = 元素個數 - 當前輪數 - 1
            for (int j = 0; j < ((sizeof(arr)/sizeof(arr[0])) - i - 1); j++){
              //如果第一個數字比第二個數字大,交換兩個數字
              if (arr[j] > arr[j + 1]){
                //交換代碼
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
              }
            }
          }
        
          //排序后結果
          cout << "排序后:" << endl;
          for (int i = 0; i < 9; i++){
            cout << arr[i] << " " ;
          }
          cout << endl;
        
          system("pause");
          return 0;
        }
        

      二維數組

      二維數組就是在一維數組上多加一個維度
      二維數組定義方式:

      • 數據類型 數組名[行數][列數];

      • 數據類型 數組名[行數][列數] = {{數據1,數據2} , {數據3,數據4}};

      • 數據類型 數組名[行數][列數] = {數據1,數據2,數據3,數據4};

      • 數據類型 數組名[ ][列數] = {數據1,數據2,數據3,數據4};

      • 示例:

        using namespace std;
        int main(){
          
          //數據類型 數組名[行數][列數];
          int arr[2][3];
          arr[0][0] = 1;
          arr[0][1] = 2;
          arr[0][2] = 3;
          arr[1][0] = 4;
          arr[1][1] = 5;
          arr[1][2] = 6;
        
          //輸出二維數組元素值
          for (int i = 0; i < (sizeof(arr)/sizeof(arr[0][0])/3); i++){
            for (int j = 0; j < (sizeof(arr)/sizeof(arr[0][0])/2); j++){
              cout << arr[i][j] << endl;
            }
          }
        

        //數據類型 數組名[行數][列數] = {{數據1,數據2} , {數據3,數據4}};
        int arr2[2][3] = {
        {1,2,3},
        {4,5,6}
        };
        for (int i = 0; i < (sizeof(arr2)/sizeof(arr2[0][0])/3); i++){
        for (int j = 0; j < (sizeof(arr2)/sizeof(arr2[0][0])/2); j++){
        cout << arr2[i][j] << " " ;
        }
        cout << endl;
        }

        //數據類型 數組名[行數][列數] = {數據1,數據2,數據3,數據4};
        int arr3[2][3] = {1,2,3,4,5,6};
        for (int i = 0; i < (sizeof(arr3)/sizeof(arr3[0][0])/3); i++){
        for (int j = 0; j < (sizeof(arr3)/sizeof(arr3[0][0])/2); j++){
        cout << arr3[i][j] << " " ;
        }
        cout << endl;
        }

        //數據類型 數組名[ ][列數] = {數據1,數據2,數據3,數據4};
        int arr4[][3] = {1,2,3,4,5,6};
        for (int i = 0; i < (sizeof(arr4)/sizeof(arr4[0][0])/3); i++){
        for (int j = 0; j < (sizeof(arr4)/sizeof(arr4[0][0])/2); j++){
        cout << arr4[i][j] << " " ;
        }
        cout << endl;
        }

        system("pause");
        return 0;

        }

      二維數組數組名

      • 查看二維數組所占內存空間

      • 獲取二維數組首地址

      • 示例:

        using namespace std;
        int main(){
        
          //查看占用內存空間大小
          int arr[2][3] = {
            {1,2,3},
            {4,5,6}
          };
          cout << "二維數組占用內存空間為:" << (sizeof(arr)) << endl;
          cout << "二維數組第一行占用內存空間為:" << sizeof(arr[0]) << endl; //arr[0]表示第一行
        
          //查看二維數組首地址
          cout << "二維數組首地址為:" << arr << endl;
        
          system("pause");
          return 0;
        }
        

        案例:考試成績統計
        要求:有三名同學(張三、李四、王五),考試成績如下表,請分別輸出三名同學的總成績

      姓名 語文 數學 英語
      張三 100 100 100
      李四 90 50 100
      王五 60 70 80

      函數

      • 作用:將一段經常使用的代碼封裝起來,減少重復代碼
      • 一個較大的程序,一般分為若干程序塊,每個模塊實現特定的功能

      函數的定義

      • 返回值類型

      • 函數名

      • 參數列表

      • 函數體語句

      • return表達式

      • 語法

        返回值類型  函數名  (參數列表){
          函數體語句
          return表達式
          }
        

        //示例:
        int add(int num1,int num2){
        int sum = num1 + num2;
        return sum;
        }

      函數的調用

      • 功能:使用定義好的函數
      • 語法:函數名(參數)
      • 示例
        using namespace std;
        int add(int num1,int num2){   //定義中的num1,num2稱為形式參數,簡稱形參
          int sum =  num1 + num2;
          return sum;
        }
        
        int main(){
          
          int a = 10;
          int b = 20;
          //調用add函數
          int sum = add(a,b);  //調用時的a,b成為實際參數,簡稱實參
          cout << "sum = " << sum << endl;
        
          system("pause");
          return 0;
        }
        

      值傳遞

      • 所謂值傳遞,就是函數調用時實參將參數數值傳入給形參

      • 值傳遞時,如果形參發生改變,并不會影響實參

      • 示例:

        using namespace std;
        
        //定義函數,實現兩個數字進行交換函數
        //如果函數不需要返回值,聲明的時候可以寫void
        void swap(int num1.int num2){
          cout << "交換前:" << endl;
          cout << "num1:" << endl;
          cout << "num2" << endl;
        
          int temp = num1;
          num1 = num2;
          num2 = temp;
        
          cout << "交換后:" << endl;
          cout << "num1" << endl;
          cout << "num2" << endl;
        
        }
        
        int main(){
        
          int a = 10;
          int b = 20;
        
          swap(a,b);
        
          system("pause");
          return 0;
        }
        

      函數的常見樣式

      • 無參無返

      • 有參無返

      • 無參有返

      • 有參有返

      • 示例:

        using namespace std;
        //函數常見樣式
        //1、無參無返
        void test01(){
          //void a = 10;  //無類型不可以創建變量,原因是因為無法分配內存
          cout << "this is test01" << endl;
          //test01();函數調用
        }
        
        //有參無返
        void test02(int a){
          cout << "this is test02 a = " << a << endl;
        }
        
        //無參有返
        int test03(){
          cout << "this is test03" << endl;
          return 1000;
        }
        
        //有參有返
        int test04(int a){
          cout << "this is test04 a = " << a << endl;
          return 1000;
        }
        
        int main(){
        
          //無參無返的函數調用
          test01();
        
          //有參無返的函數調用
          test02(100);
        
          //無參有返的函數調用
          int num = test03();
          cout << "num = " << num << endl;
        
          //有參有返的函數調用
          int num2 = test04(10000);
          cout << "num2 = " << num2 << endl;
          
          system("pause");
          return 0;
        }
        

      函數的聲明

      • 作用:告訴編譯器函數名稱及如何調用函數,函數的實際主體可以單獨定義。

      • 函數的聲明可以多次,但是函數的定義只能有一次

      • 示例

        using namespace std;
        
        //比較函數,實現兩個整型數字進行比較,返回較大的值
        //定義函數
        int max(int a,int b);           //函數的聲明
        
        int max(int a,int b){           
          return a > b ? a : b;         //函數的定義
        }
        
        int main(){
          
          int a = 10;
          int b = 20;
        
          cout << max(a,b) << endl;
        
          system("pause");
          return 0;
        }
        
        

      函數的分文件編寫

      • 函數的分文件編寫

      • 函數分文件編寫一般有四個步驟

        • 創建后綴名為 .h 的頭文件
        • 創建后綴名為 .cpp 的源文件
        • 在頭文件中寫函數的聲明
        • 在源文件中寫函數的定義
      • 示例:

         #include<iostream>
         using namespace std;
        
         //函數的分文件編寫
         //實現兩個數字進行交換的函數
         //函數的聲明
         void swap(int a,int b);
        
         //函數的定義
         void swap(int a,int b){
          int temp = a;
          a = b;
          b = temp;
          cout << "a = " << a << endl;
          cout << "b = " << b << endl;
         }
        
         int main(){
        
          int a = 10;
          int b = 20;
          swap(a,b);
        
          system("pause");
          return 0;
         }
        

        //創建后綴名為 .h 的頭文件
        //創建后綴名為 .cpp 的源文件
        //在頭文件中寫函數的聲明
        //在源文件中寫函數的定義

        //swap.h文件

        include

        using namespace std;
        //實現兩個數字交換的函數聲明
        void swap(int a,int b);

        //swap.cpp文件

        include "swap.h"

      指針

      • 作用:可以通過指針間接訪問內存
        • 內存編號是從0開始記錄的,一般用十六進制數字表示
        • 可以利用指針變量保存地址

      指針變量的定義和使用

      • 示例:
        using namespace std;
        int main(){
        
          //定義指針
          int a = 10;
        
          //指針定義的語法:數據類型 * 指針變量名
          int * p;
        
          //讓指針記錄變量 a 的地址
          p = &a;
          cout << "a的地址為:" << &a << endl;
          cout << "a的地址為:" << p << endl;
        
          //使用指針
          //可以通過解引用的方式來找到指針指向的內存
          //指針前加 * 代表解引用,找到指針指向的內存中的數據
          *p = 1000;
          cout << "a = " << a << endl;
          cout << "*p = " << *p << endl;
        
          system("pause");
          return 0;
        }
        

      指針所占內存空間

      • 指針也是一種數據類型。

      • 示例:

        using namespace std;
        int main(){
        
          int a = 10;
        
          int * p;
          p = &a;  //指針指向數據a的地址
          //在32位操作系統下,占用4個字節空間
          //在64位操作系統下,占用8個字節空間
          
          cout << "sizeof(int *) = " << sizeof(p) << endl;
          cout << *p << endl;  //解引用
          cout << sizeof(p) << endl;
          cout << sizeof(char *) << endl;
          cout << sizeof(flot *) << endl;
          cout << sizeof(double *) << endl;
        
          system("pause");
          return 0;
        }
        

      空指針和野指針

      • 空指針:指針變量指向內存中編號為0的空間

      • 用途:初始化指針變量

      • 注意:空指針指向的內存是不可以訪問的

      • 示例:

        using namespace std;
        int main(){
          //空指針用于給指針變量進行初始化
          int * p = NULL;
          //空指針是不可以進行訪問的 
          //0~255之間的內存編號是系統占用的,因此不可以訪問
          *p = 1000;  //報錯:寫入權限沖突
          system("pause");
          return 0;
        }
        
      • 野指針:指針變量指向非法的內存空間

      • 示例:

        using namespace std;
        int main(){
          //野指針變量p指向內存地址編號為0x1100的空間
          //在程序中,盡量避免出現野指針
          int * p = (int *)0x1100;
        
          //訪問野指針報錯
          cout << *p << endl;
        
          system("pause");
          return 0;
        }
        

      const修飾指針

      • const 修飾指針有三種情況:

        • const修飾指針---常量指針
        • const修飾常量---指針常量
        • const即修飾指針,又修飾常量
      • 示例:

        using namespace std;
        int main(){
        
          int a = 10;
          int b = 10;
        
          //const修飾的是指針,指針指向可以改,指針指向的值不可以更改
          //常量指針
          const int * p1 = &a;
          p1 = &b;  //正確
          *p1 = 100;  //錯誤
        
          //const修飾的是常量,指針指向不可以改,指針指向的值可以改
          //指針常量
          int * const p2 = &a;
          p2 = &b;  //錯誤
          *p2 = 20;  //正確
        
          //const即修飾指針又修飾常量,指針的指向和指針指向的值都不可以改
          const int * const p3 = &a;
          *p3 = 20;  //錯誤
          p3 = &b;   //錯誤
          *p3 = 10;  //正確
        

        system("pause");
        return 0;

        }

      指針和數組

      • 作用:利用指針訪問數組中元素
      • 示例:
        using namespace std;
        int main(){
        
          //指針和數組
          //利用指針訪問數組中的元素
        
          int arr[10] = {1,2,3,4,5,6,7,8,9,10};
          cout << "第一個元素為:" << arr[0] << endl;
        
          int * p = arr; //arr就是數組的首地址
        
          cout << "利用指針訪問第一個元素:" << *p << endl;
        
          p++;  //讓指針向后偏移4個字節 
          cout << "利用指針訪問第二個元素:" << *p << endl;
        
          cout << "利用指針遍歷數組" << endl;
          int * p2 = arr;
          for (int i = 0; i < 10; i++){
            cout << arr[i] << endl;
            cout << *p2 << endl;
            p2++;
          }
        
          system("pause");
          return 0;
        }
        

      指針和函數

      • 作用:利用指針作函數參數,可以修改實參的值

      • 示例:

        using namespace std;
        
        //實現兩個數字進行交換
        void swap01(int a,int b){
          int temp = a;
          a = b;
          b = temp;
        
          cout << "swap01 a = " << a << endl;
          cout << "swap01 b = " << b << endl;
        }
        
        void swap02(int *p1,int *p2){
          int temp = *p1;
          *p1 = *p2;
          *p2 = temp;
        }
        
        int main(){
        
          //指針和函數
          //值傳遞
          int a = 10;
          int b = 20;
          swap01(a,b);
        
          //地址傳遞
          //如果是地址傳遞,可以修飾實參
          swap02(&a,&b);   
        
          cout << "a = " << a << endl;
          cout << "b = " << b << endl;
        
          //
        
          system("pause");
          return 0;
        }
        

      指針、數組、函數

      • 案例:封裝一個函數,利用冒泡排序,實現對整型數組的升序排序

      • 例如:int arr[10] = {4,3,6,9,1,2,10,8,7,5};

      • 示例:

        //冒泡排序函數:參數1是數組的首地址,參數2是數組的長度 
        void bubbleSort(int * arr,int len)   //int * arr 也可以寫作int arr[]
        {
          for (int i = 0; i < len; i++){
            for (int j = 0; j < len - 1 -i; j++){
              if (arr[j] > arr[j+1]){
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
              }
            }
          }
        }
        
        //打印數組
        void printArray(int * arr, int len)
        {
          for (int i = 0; i < len; i++){
            cout << arr[i] << endl;
          }
        }
        
        int main(){
        
          //創建一個數組
          int arr[10] = {4,3,6,9,1,2,10,8,7,5};
        
          //數組長度
          int len = sizeof(arr) / sizeof(arr[0]);
        
          //創建函數,實現冒泡排序
          bubbleSort(arr, len)
        
          //打印排序后的數組
          printArray(arr, len);
        
          system("pause");
          return 0;
        }
        
        
        

      結構體

      • 概念:結構體屬于用戶自定義的數據類型,允許用戶存儲不同的數據類型

      結構體定義和使用

      • 語法: struct 結構體名 {結構體成員列表};

      • 通過結構體創建變量的方式有三種:

        • struct 結構體名 變量名
        • struct 結構體名 變量名 = {成員1值,成員2值...};
        • 定義結構體時順便創建變量
      • 注意:

        • 定義結構體時的關鍵字時struct,不可省略
        • 創建結構體變量時,關鍵字struct可以省略
        • 結構體變量利用操作符" . "訪問成員
      • 示例:

        using namespace std;
        #include <string>
        
        //創建學生數據類型:學生包括(姓名、年齡、分數)
        //自定義數據類型:一些類型集合組成的一個類型
        struct Student{
          //成員列表
          //姓名
          string name;
          //年齡
          int age;
          //分數
          int score;
        }s3;         //在定義結構體時順便創建結構體變量
        
        int main(){
        
          //通過學生類型創建具體學生
          //struct Student s1;
            //struct 關鍵字可以省略
            struct Student s1;
            //給s1屬性賦值,通過 . 訪問結構體變量中的屬性
            s1.name = "張三";
            s1.age = 18;
            s1.score = 100;
            cout << "姓名:" << s1.name << " 年齡:" << s1.age << " 分數:" << s1.score << endl;
        
          //struct Student S2 = {...};
          struct Student s2 = {"李四", 19 ,80};
          cout << "姓名:" << s2.name << " 年齡:" << s2.age << " 分數:" << s2.score << endl;
        
          //在定義結構體時順便創建結構體變量
          s3.name = "王五";
          s3.age = 19;
          s3.score = 90;
          cout << "姓名:" << s3.name << " 年齡:" << s3.age << " 分數:" << s3.score << endl;
        
          system("pause");
          return 0;
        }
        

      結構體數組

      • 作用:將自定義的結構體放入到數組中方便維護

      • 語法:struct 結構體名 數組名[元素個數] = {{},{},...{}};

      • 示例:

        #include <string>
        using namespace std;
        
        //結構體定義
        struct student{
          //成員列表
          string name;  //姓名
          int age;      //年齡
          int score;    //分數
        }; 
        
        int main(){
        
          //結構體數組
          struct student stuArray[3] = {
            {"張三",18,80},
            {"李四",19,90},
            {"王五",18,100}
          };
        
          //給結構體數組中的元素賦值
          stuArray[2].name = "趙六";
          stuArray[2].age = 17;
          stuArray[2].score = 95;
        
          stuArray[2] = {"錢七",18,85};
        
          //遍歷結構體數組
          for (int i = 0; i < 3; i++){
            cout << "姓名:" << stuArray[i].name
                 << "年齡:" << stuArray[i].age 
                 << "分數:" << stuArray[i].score << endl;
          }
        
          system("pause");
          return 0;
        }
        

      結構體指針

      • 作用:通過指針訪問結構體中的成員

        • 利用操作符 -> 可以通過結構體指針訪問結構體屬性
      • 示例:

        #include <string>
        using namespace std;
        
        //結構體定義
        struct student{
          //成員列表
          string name;  //姓名
          int age;      //年齡
          int score;    //分數
        };
        
        int main(){
        
          //創建學生結構體變量
          struct student s = {"張三",18,100};
        
          //通過指針指向結構體變量
          struct student * p = &s;
        
          //通過指針訪問結構體變量中的數據
          //通過結構體指針 訪問結構體中的屬性,需要利用" -> "
          cout << "姓名:" << p->name
               << "年齡:" << p->age
               << "分數:" << p->score << endl;
        
          system("pause");
          return 0;
        }
        

      結構體嵌套結構體

      • 作用:結構體中的成員可以是另一個結構體

      • 例如:每個老師輔導一個學員,一個老師的結構體中,記錄一個學生的結構體

      • 示例:

        #include <string>
        using namespace std;
        
        //學生結構體定義
        struct student{
          //成員列表
          string name;  //姓名
          int age;      //年齡
          int score;    //分數
        };
        
        //老師結構體定義
        struct teacher{
          //成員列表
          int id;  //職工編號
          string name;  //教師姓名
          int age;  //教師年齡
          struct student stu;  //子結構體  學生
        };
        
        int main(){
        
          //結構體嵌套結構體
          //創建老師
          teacher t;
          t.id = 10000;
          t.name = "老王";
          t.age = 50;
          t.stu.name = "小王";
          t.stu.age = 20;
          t.stu.score = 60;
          cout << "老師編號:" << t.id
               << "老師姓名:" << t.name
               << "老師年齡:" << t.age
               << "老師輔導的學生姓名:" << t.stu.name
               << "學生年齡:" << t.stu.age
               << "學生分數:" << t.stu.score << endl;
        
          system("pause");
          return 0;
        }
        

      結構體做函數參數

      • 作用:將結構體作為參數向函數中傳遞

      • 傳遞方式有兩種:

        • 值傳遞
        • 地址傳遞
      • 示例:

        using namespace std;
        #include <string>
        
        //學生結構體定義
        struct student{
          //成員列表
          string name;  //姓名
          int age;      //年齡
          int score;    //分數
        };
        
        void printStudent(student stu){
          stu.age =28;
          cout << "子函數中 姓名:" << stu.name 
               << "年齡:" << stu.age
               << "分數:" << stu.score
        }
        
        //打印學生信息函數
        //值傳遞
        void printStudent1(struct student s){
          cout << "子函數中打印 姓名:" << s.name << "年齡:" << s.age << "分數:" << s.score << endl;
        }
        //地址傳遞
        void printStudent2(struct student * p){
          cout << "子函數2中打印 姓名:" << p->name << "年齡:" << p->age << "分數:" << p->score << endl;
        }
        
        int main(){
        
          //結構體做函數參數
          //將學生傳入到一個參數中,打印學生身上的所有信息
        
          //創建結構體變量
          struct student s;
          s.name = "張三";
          s.age = 20;
          s.score = 85;
        
          //值傳遞
          printStudent1(s)
        
          //地址傳遞
          printStudent2(&s);
          //cout << "main函數中打印 姓名:" << s.name << "年齡:" << s.age << "分數:" << s.score << endl;
        
          system("pause");
          return 0;
        }
        

      結構體中 const 使用場景

      • 作用:用const來防止誤操作

      • 示例:

        #include <string>
        using namespace std;
        
        //學生結構體定義
        struct student{
          //成員列表
          string name;  //姓名
          int age;      //年齡
          int score;    //分數
        };
        
        //const使用場景
        //將函數中的形參改成指針,可以減少內存空間,而且不會復制新的副本出來
        void printStudent(const student * stu)  //加const防止函數體中的誤操作
        {
          //stu->age = 100; //操作失敗,因為加了const修飾
          cout << "子姓名:" << stu->name << "年齡:" << stu->age << "分數:" << stu->score << endl;
        }
        

        int main(){

        //創建結構體變量
        struct student s = { "張三",15,70};

        //通過函數打印結構體變量信息

        system("pause");
        return 0;

        }

        //算法技巧
        void allocateSpace(struct Teacher tArray[] , int len){
        string nameSeed = "ABCDE";
        for (int i = 0; i < len; i++){
        tArray[i].tName = "Teacher_";
        tArray[i].tname += nameSeed[i];
        }
        }

      C++核心編程

      內存分區模型

      • C++程序在執行時,將內存大方向劃分為4個區域
        • 代碼區:存放函數體的二進制代碼,由操作系統進行管理的
        • 全局區:存放全局變量和靜態變量以及常量
        • 棧區:由編譯器自動分配釋放,存放函數的參數值,局部變量等
        • 堆區:由程序員分配和釋放,若程序員不釋放,程序結束時由操作系統回收
      • 內存四區意義:
        不同區域存放的數據,賦予不同的生命周期,給我們更大的靈活編程

      程序運行前

      • 在程序編譯后,生成了exe可執行程序,未執行該程序前分為兩個區域

      • 代碼區:

        • 存放CPU執行的機器指令
        • 代碼區是共享的,共享的目的是對于頻繁被執行的程序,只需要在內存中有一份代碼即可
        • 代碼區是只讀的,使其只讀的原因是防止程序意外的修改了它的指令
      • 全局區:

        • 全局變量和靜態變量存放在此
        • 全局區還包含了常量區,字符串常量和其他常量也存放在此
        • 該區域的數據在程序結束后由操作系統釋放
        • 示例:
          using namespace std;
          
          //創建全局變量
          int b = 10;    //全局變量是指不在函數體內的變量
          
          //const修飾的全局變量
          const int c_g_a = 10;
          
          int main(){
          
            //創建普通局部變量
            int a = 10;
          
            //靜態變量  在普通變量前面加static,屬于靜態變量
            static int s_a = 10;
          
            //常量
            //字符串常量
            cout << (int)&"hello world" << endl;
          
            //const修飾的變量
            //const修飾的全局變量和const修飾的局部變量
          
            const int c_l_a = 10  //const修飾的局部變量
          
          
            system("pause");
            return 0;
          }
          
        
        
      • 總結:

        • C++中在程序運行前分為全局區和代碼區
        • 代碼區特點是共享和只讀
        • 全局區中存放全局變量、靜態變量、常量
        • 常量區中存放const修飾的全局變量和字符串常量

      程序運行后

      • 棧區

        • 由編譯器自動分配釋放,存在函數的參數值,局部變量等

        • 注意事項:不要返回局部變量的地址,棧區開辟的數據由編譯器自動釋放

        • 示例:

          using namespace std;
          
          //棧區數據注意事項   --- 不要返回局部變量的地址
          //棧區的數據由編譯器管理開辟和釋放
          
          int * func()   //形參數據也會放在棧區
          {
            int a = 10;  //局部變量  存放在棧區,棧區的數據在函數執行完后自動釋放
            return &a;   //返回局部變量的地址
          }
          
          int main(){
          
            //接收func函數的返回值
            int * p = func();
            cout << *p << endl;  //第一次可以打印正確的數字,是因為編譯器做了保留
            cout << *p << endl;  //第二次這個數據就不保留了
          
            system("pause");
            return 0;
          }
          
      • 堆區

        • 由程序員分配釋放,若程序員不釋放,程序結束后由操作系統回收

        • 在C++中主要利用new在堆區開辟內存

        • 示例:

          using namespace std;
          
          int * func (){
            //利用new關鍵字,可以將數據開辟到堆區
            //指針本質也是局部變量,放在棧上,指針保存的數據是放在堆區
            int * p = new int(10);
            return p;
          }
          
          int main(){
          
            //在堆區開辟數據
            int * p = func();
            cout << *p << endl;
             
            system("pause");
            return 0;
          }
          

      new操作符

      • 堆區開辟的數據,由程序員手動開辟,手動釋放,釋放利用操作符 delete

      • 語法: new 數據類型

      • 利用 new 創建的數據,會返回該數據對應的類型的指針

      • 示例:

        using namespace std;
        //new的基本語法
        int * func(){
          //在堆區創建整型數據
          //new返回的是該數據類型的指針
          int * p = new int(10);
          return p;
        }
        //在堆區利用new開辟數組
        void test01(){
          int * p = func();
          cout << *p << endl;
          //堆區的數據,由程序員管理開辟,程序員管理釋放
          //如果想釋放堆區的數據,利用關鍵字 delete
          delete p;
          cout << *p << endl;  //錯誤:引發異常,讀取訪問出錯。因為內存已經被釋放,再次訪問就是非法操作,會報錯
        }
        
        //在堆區利用new開辟數組
        void test02(){
          //創建10整型數組的數組,在堆區
          int * arr = new int[10];   //10代表數組有10個元素
        
          for (i = 0; i < 10; i++){
            arr[i] = i + 100;  //給10個元素賦值  100~109
          }
          for (int i = 0; i < 10; i++){
            cout << arr[i] << endl;
          }
        
          //釋放堆區數組
          //釋放數組的時候,要加[]才可以
          delete [] arr;
        }
        int main(){
        
          //調用test02()
          test02();
        
          system("pause");
          return 0;
        }
        

      引用

      • 作用:給變量起別名

      • 語法:數據類型 &別名 = 原名

      • 示例:

        using namespace std;
        int main(){
        
          //引用的基本語法
          //數據類型 &別名 = 原名
          int a = 10;
        
          //創建引用
          int &b = a;
        
          cout << "a = " << a << endl;
          cout << "b = " << b << endl;
        
          b = 100;
        
          cout << "a = " << a << endl;
          cout << "b = " << b << endl;
        
          system("pause");
          return 0;
        }
        

      引用注意事項

      • 引用必須初始化

      • 引用在初始化后,不可以改變

      • 示例:

        using namespace std;
        int main(){
        
          int a = 10;
          int b = 10;
          //int &c;   //錯誤,引用必須初始化
          int &c = a; //一旦初始化后,就不可以更改
          c = b; //這是賦值操作,不是更改引用
        
          cout << "a = " << a << endl;
          cout << "b = " << b << endl;
          cout << "c = " << c << endl;
        
          system("pause");
          return 0;
        }
        

      引用做函數參數

      • 作用:函數傳參時,可以利用引用的技術讓形參修飾實參

      • 優點:可以簡化指針修改實參

      • 示例:

        using namespace std;
        
        //值傳遞
        void mySwap01(int a, int b){
          int temp = a;
          a = b;
          b = temp;
          cout << "mySwap01 a = " << a << endl;
          cout << "mySwap01 b = " << b << endl;
        }
        
        //地址傳遞
        void mySwap02(int * a; int * b){
          int temp = *a;
          *a = *b;
          *b = temp;
          cout << "mySwap02 a = " << a << endl;
          cout << "mySwap02 b = " << b << endl;
        }
        
        //引用傳遞
        void mySwap03(int &a, int &b){
          int temp = a;
          a = b;
          b = temp;
        }
        
        int main(){
        
          int a = 10;
          int b = 20;
        
          mySwap01(a,b);        //值傳遞,形參不會修飾實參
        
          mySwap02(&a,&b);      //地址傳遞,形參會修飾實參
        
          mySwap03(a,b);        //引用傳遞,形參會修飾實參
        
          cout << "a = " << a << endl;
          cout << "b = " << b << endl;
        
          system("pause");
          return 0;
        }
        
      • 總結:通過引用參數產生的效果同按地址傳遞是一樣的。引用的語法更清楚簡單

      引用做函數返回值

      • 作用:引用是可以作為函數的返回值存在的

      • 注意:不要返回局部變量引用

      • 用法:函數調用作為左值

      • 示例:

        using namespace std;
        
        //引用做函數的返回值
        //不要返回局部變量的引用
        int& test01(){
          int a = 10; //局部變量,存放在四區中的棧區
          return a;
        }
        
        //函數的調用可以作為左值
        int& test02(){
          static int a = 10;  //靜態變量存放在全局區,全局區上的數據在程序結束后系統釋放
          return a;
        }
        
        int main(){
        
          int &ref = test01();
          cout << "ref = " << ref << endl;   //第一次結果準確,是因為編譯器做了保留
          cout << "ref = " << ref << endl;  //第二次結果錯誤,因為a的內存已經釋放
        
          int &ref2 = test02();
          cout << "ref2 = " << ref2 << endl;
          cout << "ref2 = " << ref2 << endl;
          
          test02() = 1000;  //如果函數的返回值是引用,這個函數調用可以作為左值
        
          cout << "ref2 = " << ref2 << endl;
          cout << "ref2 = " << ref2 << endl;
        
          system("pause");
          return 0;
        }
        

      引用的本質

      • 本質:有用的本質再C++內部實現是一個指針常量

      • 示例:

        using namespace std;
        
        //發現是引用,轉換為int * const ref = &a;
        void func(int& ref){
          ref = 100;  //ref是引用,轉換為*ref = 100;
        }
        int main(){
        
          int a = 10;
          //自動轉換為 int * const ref = &a;指針常量是指針指向不可改,也說明為什么引用不可更改
          int& ref = a;
          ref = 20;  //內部發現ref是引用,自動幫我們轉換為:*ref = 20;
          cout << "a : " << a << endl;
          cout << "ref: " << ref << endl;
          
          system("pause");
          return 0;
        }
        

      常量引用

      • 作用:常量引用主要用來修飾形參,防止誤操作

      • 再函數形參列表中,可以加 const 修飾形參,防止形參改變實參

      • 示例:

        using namespace std;
        //引用使用的場景,通常用來修飾形參
        void showValue(const int& v){
          //v += 10;
          cout << v << endl;
        }
        
        int main(){
        
          //常量引用
          //使用場景:用來修飾形參,防止誤操作
        
          int a = 10;
          //int & ref = 10;  引用本身需要一個合法的內存空間,因此這行錯誤
        
          const int & ref = 10;  
          //加入const就可以了,編譯器優化代碼,int temp = 10; const int & ref = temp;
        
          //ref = 20;    //加入const之后變為只讀,不可以修改。
          showValue(a);
          cout << ref << endl;
        
          system("pause");
          return 0;
        }
        

      函數提高

      函數默認參數

      • 在C++中,函數的形參列表中的形參是可以有默認值的。

      • 語法:返回值類型 函數名 (參數 = 默認值){}

      • 示例:

        using namespace std;
        
        //函數默認參數
        //如果我們傳入數據,就用自己的數據,如果沒有,那么用默認值
        int func(int a, int b = 10; int c = 10){
          return a + b + c;
        }
        
        //1、如果某個位置參數有默認值,那么從這個位置往后,從左往右,必須都要有默認值
        //2、如果函數聲明有默認值,函數實現的時候就不能有默認參數
        
        int func2(int a = 10, int b = 10);
        int func2(int a, int b){
          return a + b;
        }
        
        int main(){
          system("pause");
          return 0;
        }
        

      函數占位參數

      • C++中函數的形參列表里可以有占位參數,用來做占位,調用函數時必須填補該位置

      • 語法:返回值類型 函數名(數據類型){}

      • 示例:

        using namespace std;
        
        //函數占位參數,占位參數也可以有默認參數
        void func(int a, int){
          cout << "this is func" << endl;
        }
        
        int main(){
        
          func(10,10);//占位參數必須填補
          system("pause");
          return 0;
        }
        

      函數重載

      函數重載概述
      • 作用:函數名可以相同,提高復用性

      • 函數重載滿足條件:

        • 同一個作用域下
        • 函數名稱相同
        • 函數參數類型不同或者個數不同或者順序不同
      • 注意:函數的返回值不可以作為函數重載的條件

      • 示例:

        using namespace std;
        
        //函數重載需要函數都在同一個作用域下
        void func(){ 
          cout << "func的調用" << endl;
        }
        
        void func(int a){ 
          cout << "func(int a)的調用" << endl;
        }
        
        void func(double a){ 
          cout << "func(double a)的調用" << endl;
        }
        
        int main(){
        
          func();
          func(10);
          func(3.14)
        
          system("pause");
          return 0;
        }
        
      函數重載注意事項
      • 引用作為重載條件

      • 函數重載碰到函數默認參數

      • 示例:

        using namespace std;
        
        //引用作為重載條件
        void func(int &a){      //int &a = 10;  不合法
          cout << "func (int &a)" << endl;
        }
        
        void func(const int &a){    //const int &a = 10;
          cout << "func (const int &a)" << endl;
        }
        
        //函數重載碰到函數默認參數
        void func2(int a, int b = 10){      
          cout << "func2 (int a, int b)" << endl;
        }
        
        void func2(int a){      
          cout << "func2 (int a)" << endl;
        }
        
        int main(){
        
          //int a = 10;
          //func(a);
        
          func(10);
        
          //func2(10);  //當函數重載碰到默認參數,出現二義性,報錯,盡量避免這種情況
        
          system("pause");
          return 0;
        }
        

      類和對象

      • C++面向對象的三大特性:封裝、繼承、多態

      • C++認為萬事萬物都皆為對象,對象上有其屬性和行為

      • 例如:

        人可以作為對象,屬性有姓名、年齡、身高、體重...,行為有走、跑、跳、吃飯、唱歌...
        車也可以作為對象,屬性有輪胎、方向盤、車燈...,行為有載人、放音樂、開空調...
        具有相同性質的對象,我們可以抽象稱為類,人屬于人類,車屬于車類
        

      封裝

      封裝的意義
      • 封裝是C++面向對象三大特性之一

      • 封裝的意義

        • 將屬性和行為作為一個整體,表現生活中的事務
        • 將屬性和行為加以權限控制
      • 封裝意義一:

        在設計類的時候,屬性和行為寫在一起,表現事物
        
        • 語法:class 類名{ 訪問權限: 屬性 / 行為};

        • 示例1:設計一個圓類,求圓的周長

          using namespace std;
          
          //圓周率
          const double PI = 3.14
          
          //設計一個圓類,求圓的周長
          //class代表設計一個類,類后面緊跟著的就是類名稱
          class Circle{
          
          //訪問權限
          //公共權限
          public:
          //屬性
          //半徑
          int m_r;
          //行為
          //獲取圓的周長
          double calculateZC(){
            return 2 * PI * m_r;
          }
          };
          
          int main(){
          
          //通過圓類 創建具體的圓(對象)
          //實例化  (通過一個類,創建一個對象的過程)
          Circle c1;
          
          //給圓對象的屬性進行賦值
          c1.m_r = 10;
          
          cout << "圓的周長為:" << c1.calculateZC() << endl;
          
          system("pause");
          return 0;
          }
          
          //封裝的意義
          //將屬性和行為作為一個整體,用來表現生活中的事物
          
        • 示例2:

          using namespace std;
          #include <string>;
          
          //學生類
          class Student{
          
          //權限
          public:
          
          //類中的屬性和行為,我們統一稱為成員
          //屬性  成員屬性 成員變量
          //行為  成員函數  成員方法
          
          //屬性
          string m_Name;
          int m_ID;
          
          //行為
          void showStudent(){
            cout << "姓名" << m_Name << "學號" << m_ID << endl;
          }
          
          //給姓名賦值
          
          void setName(string name){
            m_Name = name;
          }
          
          }
          
          int main(){
          
          //創建一個具體學生   實例化對象
          Student s1;
          
          //給s1對象進行屬性賦值操作
          //s1.m_Name = "張三";
          s1.setName("張三");
          s1.m_ID = 1;
          
          //現實學生信息
          s1.showStudent();
          
          system("pause");
          return 0;
          }
          
      • 封裝意義二:

        • 類在設計時,可以把屬性和行為放在不同的權限下,加以控制

        • 訪問權限有三種

          • public 公共權限
          • protected 保護權限
          • private 私有權限
        • 示例:

          using namespace std;
          
          //訪問權限
          //公共權限 public         成員類內可以訪問  類外可以訪問
          //保護權限 protected      成員類內可以訪問  類外不可以訪問  繼承父子關系可以訪問
          //私有權限 private        成員類內可以訪問  類外不可以訪問  繼承父子關系不可以訪問
          
          class Person{
          
            public:
            //公共權限
            string m_name;  //姓名
          
            protected:
            //保護權限
            string m_Car;  //汽車
          
            private:
            //私有權限
            int m_Password;  //銀行卡密碼
          
            public:
            void func(string a, string b. int c){
              m_Name = a;
              m_Car = b;
              m_Password = c;
            }
          };
          int main(){
          
            //實例化一個具體對象
            Person p1;
            p1.m_Name = "李四";
            p1.m_Car = "奔馳"   //報錯,保護權限內容,在類外訪問不到
            p1.m_Password = 123;  //報錯,私有權限內容,在類外訪問不到
          
            p1.func("張三", "拖拉機", 123456);  //可以訪問,因為兩個私有權限在public共有權限套用下,屬于類內
          
            system("pause");
            return 0;
          }
          
      struct和class區別
      • 在C++中struct和class唯一的區別就在于默認的訪問權限不同

      • 區別:

        • struct默認權限為共有
        • class默認權限為私有
      • 示例:

        class c1{
          int m_A;  //默認是私有權限  private
        };
        struct c2{
          int m_A;  //默認是公有權限  public
        };
        
      成員屬性設置為私有
      • 優點1:將所有成員屬性設置為私有,可以主機控制讀寫權限

      • 優點2:對于寫權限,我們可以檢測數據的有效性

      • 示例:

        using namespace std;
        #include <string>
        //成員屬性設置為私有
        //1、可以主機控制讀寫權限
        //2、對于寫權限可以檢測數據的有效性
        
        //設計人類
        class Person{
        
          public:
        
          //設置姓名 
          void setName(string name){
            m_Name = name;
          }
        
          //獲取姓名
          string getName(){
            return m_Name;   //不能直接反悔name,因為name只在setName里有生存周期;
          }
        
          //獲取年齡  只讀權限
          int getAge(){
            m_Age = 0;   //初始化為0歲
            return m_Age;
          }
          //設置年齡  可寫(范圍0-150)
          void setAge(int Age){
            if (age < 0 || age > 150){
              m_Age = 0;
              cout << "輸入年齡有誤!" << endl;
              return;
            }
            m_Age = Age;
          }
        
          //設置情人  只寫權限
          void setLover(string lover){
            m_Lover = lover;
          }
        
          private:
        
          //姓名  可讀可寫
          string m_Name;
        
          //年齡  只讀
          int m_Age;
        
          //情人  只寫
          string m_Lover;
        
        };
        
        int main(){
        
          Person p;
          p.setName("張三");   //正確,可以寫
        
          cout << "姓名為:" << p.getName << endl;  //正確,可以讀
        
          p.setAge(18);  //正確,可以寫
          cout << "年齡為:" << p.getAge << endl;  //正確,可以讀
        
          //設置情人
          p.setLover("蒼井");  //正確,可以寫
          cout << "情人為:" << p.getLover << endl;  //錯誤,不可以讀
        
          system("pause");
          return 0;
        }
        
      • 案例1:設計立方體類

        • 設計立方體類
        • 求出立方體的面積和體積
        • 分別用全局函數和成員函數判斷兩個立方體是否相等
        • m_L:長、m_W:寬、m_H:高
      • 示例:

        using namespace std;
        
        //創建立方體類
        class Cub{
        
          public:
        
          //行為
          //獲取立方體面積
          int calculateS(){
            return 2 * m_L * m_W + 2 * m_W * m_H + 2 * m_L * m_H;
          }
        
          //獲取立方體體積
          int calculateV(){
            return m_L * m_W * m_H;
          }
        
          //設置獲取長寬高
          //設置長
          void setL(int L){
            m_L = L;
          }
        
          //獲取長
          int getL(){
            return m_L;
          }
        
          //設置高
          void setH(int H){
            m_H = H;
          }
        
          //獲取高
          int getLH(){
            return m_H;
          }
        
          //設置寬
          void setLW(int W){
            m_W = W;
          }
        
          //獲取寬
          int getW(){
            return m_W;
          }
        
          //利用成員函數判斷兩個立方體是否相等
          bool isSnameByClass(Cube &c){
            if(m_L == c.getL() && m_W == c.getW() && m_H == c.getH()){
               return true;
            }
            return false;
          }
        
          //屬性 設置為私有 
          private:
          int m_L;  //長
          int m_W;  //寬
          int m_H;  //高
        
        };
        
        //利用全局函數判斷,兩個立方體是否相等
        bool isSame(Cube &c1 , Cube &c2){        //利用 & 引用的方式去除數據緩存步驟
          if(c1.getL() == c2.getL() && c1.getW() == c2.getW() && c1.getH() == c2.getH()){
            return true;
          }
          return false;
        }
        
        int main(){
        
          //創建立方體對象
          Cube c1;
          c1.setL(10);
          c1.setW(10);
          c1.setH(10);
        
          cout << "c1的面積為:" << c1.calculateS() << endl; 
          cout << "c1的體積為:" << c1.calculateV() << endl; 
        
          //創建第二個立方體
          Cube c2;
          c2.setL(10);
          c2.setW(10);
          c2.setH(10);
        
          cout << "c2的面積為:" << c2.calculateS() << endl; 
          cout << "c2的體積為:" << c2.calculateV() << endl;
          
          //利用全局函數判斷
          bool ret = isSame(c1,c2);
          if(ret){
            cout << "c1和c2是相等的" << endl;
          }else{
            cout << "c1和c2是不相等的" << endl;
          }
        
          //利用成員函數判斷
          ret = c1.isSameByClass(c2);
          if(ret){
            cout << "成員判斷:c1和c2是相等的" << endl;
          }else{
            cout << "成員判斷c1和c2是不相等的" << endl;
          }
        
          system("pause");
          return 0;
        }
        
      • 練習案例2:點和圓的關系

        • 設計一個圓形類(Circle)和一個點類(Point),計算點和圓的關系
      • 示例:

        #include <iostream>
        using namespace std;
        
        //點和圓關系案例
        //點類
        class Point {
        public:
          //設置x
          void setX(int x) {
              m_X = x;
          }
          //獲取x
          int getX() {
              return m_X;
          }
          //設置y
          void setY(int y) {
              m_X = y;
          }
          //獲取y
          int getY() {
              return m_Y;
          }
        private:
          int m_X;
          int m_Y;
        };
        
        //圓類
        class Circle {
        public:
        //設置半徑
          void setR(int r) {
              m_R = r;
          }
          //獲取半徑
          int getR() {
              return m_R;
          }
          //設置圓心
          void setCenter(Point center) {
              m_Center = center;
          }
          //獲取圓心
          Point getCenter() {
              return m_Center;
          }
        private:
          int m_R;  //半徑
          Point m_Center;  //圓心
        };
        
        //判斷點和圓關系
        void inInCircle(Circle& c, Point& p) {
          //計算兩點之間的平方
          int distance =
              (c.getCenter().getX() - p.getX()) * (c.getCenter().getX() - p.getX()) +
              (c.getCenter().getY() - p.getY()) * (c.getCenter().getY() - p.getY());
        
          //計算半徑的平方
          int rDistance = c.getR() * c.getR();
        
          //判斷關系
          if (distance == rDistance) {
              cout << "點在圓上" << endl;
          }
          else if (distance > rDistance) {
              cout << "點在圓外" << endl;
          }
          else
          {
              cout << " 點在圓內" << endl;
          }
        }
        int main()
        {
          //創建圓
          Circle c;
          c.setR(10);
          Point center;
          center.setX(10);
          center.setY(0);
          c.setCenter(center);
          //創建點
          Point p;
          p.setX(10);
          p.setY(10);
          //判斷關系
          inInCircle(c, p);
        
          system("pause");
          return 0;
        }
        

      對象的初始化和清理

      • 生活中我們買的電子產品都基本會有出廠設置,在某一天我們不用時候也會刪除一些自己信息數據保證安全
      • 在C++中的面向對象來源于生活,每個對象也都會有初始設置以及對象銷毀前的清理數據的設置
      構造函數和析構函數
      • 對象的初始化和清理也是兩個非常重要的安全問題

        • 一個對象或者變量沒有初始狀態,對其使用后果是未知
        • 同樣的使用完一個對象或變量,沒有及時清理,也會造成一定的安全問題
      • C++利用了構造函數和析構函數解決上述問題,這兩個函數將會被編譯器自動調用,完成對象初始化和清理工作。

      • 對象的初始化和清理工作是編譯器強制要我們做的事情,因此如果我們不提供構造和析構,編譯器會提供

      • 編譯器提供的構造函數和析構函數是空實現。

        • 構造函數:主要作用在于創建對象時為對象的成員屬性賦值,構造函數由編譯器自動調用,無需手動調用。
        • 析構函數:主要作用在于對象銷毀前系統自動調用,執行一些清理工作。
      • 構造函數語法:類名(){}

        • 構造函數沒有返回值也不寫void
        • 函數名稱與類名相同
        • 構造函數可以有參數,因此可以發生重載
        • 程序在調用對象時候會自動調用構造,無需手動調用,而且只會調用一次
      • 析構函數語法:~類名(){}

        • 析構函數沒有返回值也不寫void
        • 函數名稱與類名相同,在名稱前加上符號 ~
        • 析構函數不可以有參數,因此不可以發生重載
        • 程序在對象銷毀前會自動調用析構,無需手動調用,而且只會調用一次
      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //對象的初始化和清理
        //1、構造函數 進行初始化操作
        class Person {
        public:
          //1.1、構造函數
          //沒有返回值 不用寫void
          //函數名 與類名相同
          //構造函數可以有參數,可以發生重載
          //創建對象的時候,構造函數會自動調用,而且只調用一次
          Person() {
              cout << "Person 構造函數的調用" << endl;
          }
        
          //2、析構函數 進行清理的操作
          //沒有返回值 不寫void
          //函數名和類名相同 在名稱前面加 ~
          //析構函數不可以有參數的,不可以發生重載
          //對象在銷毀前,會自動調用析構函數,而且只會調用一次
          ~Person() {
              cout << "Person的析構函數調用" << endl;
          }
        };
        
        //構造和析構都是必須有的實現,如果我們自己不提供,編譯器會提供一個空實現的構造和析構
        void test01() {
          Person p; //在棧上的數據,test01執行完畢后,釋放這個對象
        }
        int main()
        {
          test01();
        
          //Person p;
        
          system("pause");
          return 0;
        }
        
      構造函數的分類及調用
      • 兩種分類方式

        • 按參數分為:有參構造和無參構造
        • 按類型分為:普通構造和拷貝構造
      • 三種調用方式

        • 括號法
        • 顯示法
        • 隱式轉換法
      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //1、構造函數的分類及調用
        //分類
        //按照參數分類   無參構造函數(默認構造)和有參構造函數
        //按照類型分類   普通構造函數和拷貝構造函數
        
        class Person {
        public:
          //構造函數
          Person() {                 //無參構造函數
              cout << "Person的無參構造函數調用" << endl;
          }
        
          Person(int a) {            //有參構造函數
              age = a;
              cout << "Person的有參構造函數調用" << endl;
          }
        
          //拷貝構造函數
          Person(const Person &p) {
              //將傳入的所有屬性,拷貝到參數身上
              age = p.age;
              cout << "Person的拷貝構造函數調用" << endl;
          }
        
          ~Person() {                //析構函數
              cout << "Person的析構函數調用" << endl;
          }
        
          int age;
        };
        
        //調用 
        void test01() {
        
          //1、括號法
          //Person p1;  //默認構造函數調用
          //Person p2(10); //有參構造函數
          //Person p3(p2);  //拷貝構造函數
          //注意事項
          //調用默認構造函數的時候,不要加()
          //因為下面這行代碼,編譯器會認為式一個函數的聲明,不會認為在創建對象
          //Person p1();
          /*cout << "p2的年齡為:" << p2.age << endl;
          cout << "p3的年齡為:" << p3.age << endl;*/
        
          //2、顯示法
          //Person p1;
          //Person p2 = Person(10);  //有參構造
          //Person p3 = Person(p2);  //拷貝構造
          /*Person(10);*/  //匿名對象  特點:當前行執行結束后,系統會立即回收掉匿名對象
          //cout << "aaaa" << endl;
          //注意事項2
          //不要利用拷貝構造函數 初始化匿名對象,編譯器會認為Person(p3)等價于Person p3(對象聲明)
          /*Person(p3);*/
        
          //3、隱式轉換法
          Person p4 = 10;  //相當于寫了 Person p4 = Person(10); 相當于有參構造
          Person p5 = p4;  //拷貝構造
        }
        int main()
        {
          test01();
        
          system("pause");
          return 0;
        }
        
      拷貝構造函數調用時機
      • C++種拷貝構造函數調用時機通常有三種情況

        • 使用一個已經創建完畢的對象來初始化一個新對象
        • 值傳遞的方式給函數參數傳值
        • 以值方式返回局部對象
      • 示例

        #include <iostream>
        using namespace std;
        #include <string>
        
        //拷貝構造函數調用時機
        
        class Person {
        public:
          
          Person() {                 //無參構造函數
              cout << "Person的無參構造函數調用" << endl;
          }
        
          Person(int age) {            //有參構造函數
              m_Age = age;
              cout << "Person的有參構造函數調用" << endl;
          }
        
          //拷貝構造函數
          Person(const Person & p) {
              //將傳入的所有屬性,拷貝到參數身上
              m_Age = p.m_Age;
              cout << "Person的拷貝構造函數調用" << endl;
          }
        
          ~Person() {                //析構函數
              cout << "Person的析構函數調用" << endl;
          }
        
          int m_Age;
        };
        
        //1、使用一個已經創建完畢的對象來初始化一個新對象
        //void test01() {
        //    Person p1(20);  //有參構造函數
        //    Person p2(p1);  //拷貝構造函數
        //
        //    cout << "p2的年齡為" << p2.m_Age << endl;
        //}
        
        //2、值傳遞的方式給函數參數傳值
        //void doWork(Person p) {
        //
        //}
        //
        //void test02() {
        //    Person p;
        //    doWork(p);
        //}
        
        //3、值方式返回局部對象
        Person doWork2() {
          Person p1;
          cout << (int*)&p1 << endl;
          return p1;
        }
        
        void test03() {
          Person p = doWork2();
          cout << (int*)&p << endl;
        }
        
        int main()
        {
          //test01();
        

        system("pause");
        return 0;

        }

      構造函數調用規則
      • 默認情況下,C++編譯器至少給一個類添加3個函數
        • 默認構造函數(無參,函數體為空)
        • 默認析構函數(無參,函數體為空)
        • 默認拷貝構造函數,對屬性進行值拷貝
      • 構造函數調用規則如下
        • 如果用戶定義有參構造函數,C++不在提供默認無參構造,但是會提供默認拷貝構造
        • 如果用戶定義拷貝構造函數,C++不會再提供其他構造函數
      • 示例:
        #include <iostream>
        using namespace std;
        #include <string>
        
        //構造函數的調用規則
        //1、創建一個類,C++編譯器會給每個類都添加至少三個函數
        //默認構造(空實現)
        //析構函數(空實現)
        //拷貝構造(空實現)
        
        //2、如果我們寫了有參構造函數,編譯器就不再提供默認構造,依然提供拷貝構造
        //如果我們寫了拷貝構造函數,編譯器就不再提供其他普通構造函數
        
        class Person {
        public:
          
          Person() {                 //無參構造函數
             cout << "Person的無參構造函數調用" << endl;
          }
        
          Person(int age) {            //有參構造函數
              m_Age = age;
              cout << "Person的有參構造函數調用" << endl;
          }
        
          //拷貝構造函數
          Person(const Person & p) {
              //將傳入的所有屬性,拷貝到參數身上
              m_Age = p.m_Age;
              cout << "Person的拷貝構造函數調用" << endl;
          }
        
          ~Person() {                //析構函數
              cout << "Person的析構函數調用" << endl;
          }
        
          int m_Age;
        };
        
        void test01() {
          Person p;
          p.m_Age = 18;
          Person p2(p);
        
          cout << "p2的年齡為" << p2.m_Age << endl;
        }
        
        void test02() {
          Person p;
        }
        
        int main()
        {
          //test01();   //示例1
          test02();
        
          system("pause");
          return 0;
        }
        
      深拷貝與淺拷貝
      • 深淺拷貝是面試經典問題,也是常見的一個坑

      • 淺拷貝:簡單的賦值拷貝操作

      • 深拷貝:在堆區重新申請空間,進行拷貝操作

      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //深拷貝與淺拷貝
        //淺拷貝帶來的問題就是堆區的內存重復釋放
        //淺拷貝的問題要利用深拷貝進行解決
        
        class Person {
        public:
          
          Person() {                 //無參構造函數
             cout << "Person的無參構造函數調用" << endl;
          }
        
          Person(int age,int height) {            //有參構造函數
              m_Age = age;
              m_Height = new int(height);
              cout << "Person的有參構造函數調用" << endl;
          }
        
          //自己實現拷貝構造函數解決淺拷貝帶來的問題
          Person(const Person &p) {
              cout << "Person拷貝構造函數調用" << endl;
              //將傳入的所有屬性,拷貝到參數身上
              m_Age = p.m_Age;
              //m_Height = p.m_Height;   編譯器默認實現的就是這行代碼
              //深拷貝操作
              m_Height = new int(*p.m_Height);
          }
        
          //析構代碼,將堆區開辟數據做釋放操作
          //析構時候,構造函數執行先進后出,誰先執行誰最后釋放
          ~Person() {                //析構函數
              if (m_Height != NULL) {
                  delete m_Height;  //清空堆區內存
                  m_Height = NULL;  //防止野指針出現
              }
              cout << "Person的析構函數調用" << endl;
          }
        
          int m_Age;      //年齡
          int *m_Height;  //身高
        };
        
        void test01() {
          Person p1(18 ,160);
          cout << "p1的年齡為" << p1.m_Age << "身高為:" << *p1.m_Height << endl;
        
          Person p2(p1);
          cout << "p1的年齡為" << p2.m_Age << "身高為:" << *p2.m_Height << endl;
        }
        
        void test02() {
          Person p;
        
        }
        
        int main()
        {
          test01();   //示例1
          test02();
        
          system("pause");
          return 0;
        }
        
      初始化列表
      • 作用:C++提供了初始化列表語法,用來初始化屬性

      • 語法:構造函數():屬性1(值1),屬性2(值2)...{}

      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //初始化列表
        
        class Person {
        public:
          
          //傳統初始化操作
          /*Person(int a, int b, int c) {
              m_A = a;
              m_B = b;
              m_C = c;
          }*/
        
          //初始化列表初始化屬性
          Person(int a, int b, int c) :m_A(a), m_B(b), m_C(c) {
            cout << "m_A = " << m_A << endl;
            cout << "m_B = " << m_B << endl;
            cout << "m_C = " << m_C << endl;
          }
        private:
          int m_A;
          int m_B;
          int m_C;
        };
        
        void test01() {
          //Person p(10, 20, 30);
          Person p(30,20,10);
          
        }
        
        int main()
        {
          test01();   //示例1
        
          system("pause");
          return 0;
        }
        
      類對象作為類成員
      • C++類中的成員可以是另一個類的對象,我們稱該成員為 對象成員

      • 示例:

        class A{}
        class B{
          A a;
        }
        
      • B類中有對象A作為成員,A為對象成員

      • A與B的構造和析構的順序示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //類對象作為類成員
        
        //手機類
        class Phone {
        public:
        
          Phone(string pName) {
              m_PName = pName;
              cout << "Phone的構造函數調用" << endl;
          }
        
          ~Phone() {
              cout << "Phone的析構函數調用" << endl;
          }
        

        //手機品牌名稱
        string m_PName;

        };

        //人類
        class Person {
        public:

        //Phone m_Phone = pName 隱式轉換法
        Person(string name, string pName) :m_Name(name), m_Phone(pName) {
        cout << "Person的構造函數調用" << endl;
        }

        ~Person() {
        cout << "Person的析構函數調用" << endl;
        }

        //姓名
        string m_Name;
        //手機
        Phone m_Phone;

        };

        //當其他的類的對象作為本類成員,構造時候先構造類對象,再構造自身。
        //析構的順序與構造的順序相反
        void test01() {
        Person p("張三", "蘋果");
        cout << p.m_Name << "拿著" << p.m_Phone.m_PName << endl;
        }

        int main()
        {
        test01(); //示例1

        system("pause");
        return 0;

        }

      靜態成員
      • 靜態成員就是再成員變量和成員函數前加上關鍵字static,稱為靜態成員

      • 靜態成員分成:

        • 靜態成員變量
          • 所有對象共享同一份數據
          • 在編譯階段分配內存
          • 類內聲明,類外初始化
        • 靜態成員函數
          • 所有對象共享同一個函數
          • 靜態成員函數只能訪問靜態成員變量
      • 示例1:靜態成員變量

        #include <iostream>
        using namespace std;
        #include <string>
        //靜態成員變量
        class Person {
        public:
          //1、所有對象都共享同一份數據
          //2、編譯階段就分配內存
          //3、類內聲明,類外初始化操作
          static int m_A;
        
          //靜態成員變量也是有訪問權限的
        private:
          static int m_B;
        };
        
        int Person:: m_A = 100;    //類外初始化
        
        int Person::m_B = 300;
        
        void test01() {
          Person p;
          //打印出來100
          cout << p.m_A << endl;
        
          Person p2;
          p2.m_A = 200;
          //打印出來200
          cout << p2.m_A << endl;
        }
        
        void test02() {
          //靜態成員變量 不屬于某個對象上,所有對象都共享同一份數據
          //因此靜態成員變量有兩種訪問方式
        
          //1、通過對象進行訪問
          Person p;
          cout << p.m_A << endl;
        
          //2、通過類名進行訪問
          cout << Person::m_A << endl;
        
          //cout << Person::m_B << endl;  類外訪問不到私有靜態成員變量
        }
        
        int main()
        {
          //test01();   //test01
          test02();     //test02
        
          system("pause");
          return 0;
        }
        
      • 示例2:靜態成員函數

        #include <iostream>
        using namespace std;
        #include <string>
        
        //靜態成員函數
        //所有對象共享同一個函數
        //靜態成員函數只能訪問靜態成員變量
        
        class Person {
        public:
        
          //靜態成員函數
          static void func() {
              m_A = 100;
              //m_B = 200;  靜態成員函數不可以訪問非靜態成員變量
              cout << "static void func調用" << endl;
          }
        
          //靜態成員變量
          static int m_A;
        
          //非靜態成員變量
          int m_B;    
        
          //靜態成員函數也是有訪問權限的
        private:
          static void func2() {
              cout << "static void fun2調用" << endl;
          }
        };
        
        int Person::m_A = 0;
        
        //有兩種訪問方式
        void test01() {
          //1、通過對象訪問
          Person p;
          p.func();
        
          //2、通過類名訪問
          Person::func();
        
          //Person::func2();  類外訪問不到私有靜態成員函數
        }
        
        int main()
        {
          //test01();   //示例1
        
          system("pause");
          return 0;
        }
        

      C++對象模型和this指針

      成員變量和成員函數分開存儲
      • 在C++中,類內的成員變量和成員函數分開存儲,只有非靜態成員變量才屬于類的對象上

      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //成員變量和成員函數是分開存儲的
        
        class Person {
          int m_A;  //非靜態成員變量  屬于類的對象上面
        
          static int m_B;   //靜態成員變量 不屬于類對象上
        
          //非靜態成員函數  不屬于類的對象上
          void func() {
        
          }
        
          //靜態成員函數 不屬于類的對象上
          static void func2() {
        
          }
        };
        
        int Person::m_B = 10;
        
        //void test01() {
        //    Person p;
        //
        //    //空對象占用內存空間為:1字節
        //    //C++編譯器會給每個空對象也分配一個字節空間,是為了區分空對象占內存的位置
        //    //每個空對象也應該有一個獨一無二的內存地址
        //    cout << "size of p = " << sizeof(p) << endl;
        //}
        
        void test02() {
          Person p;
          //
          cout << "size of p = " << sizeof(p) << endl;
        }
        
        int main()
        {
          //test01();   //示例1
        
          system("pause");
          return 0;
        }
        
      this指針概念
      • 在C++中成員變量和成員函數是分開存儲的

      • 每一個非靜態成員函數只會生成一份函數實例,多個同類型的對象會共用一塊代碼

      • C++通過提供特殊的對象指針,this指針解決區分哪個對象調用自己的代碼。

      • this指針指向被調用的成員函數所屬的對象

      • this指針式隱含每一個非靜態成員函數內的一種指針

      • this指針不需要定義,直接使用

      • this指針的用途

        • 當形參和成員變量同名時,可用this指針來區分
        • 在類的非靜態成員函數中返回對象本身,可使用return *this
      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        class Person {
        public:
        
          Person(int age) {
              //this指針指向被調用的成員函數所屬的對象
              this->age = age;
          }
        
          Person& PersonAddAge(Person &p) {
              this->age += p.age;
        
              //this指向p2的指針,而*this指向的就是p2這個對象本體 
              return *this;
          }
          int age;
        };
        
        //1、解決名稱沖突
        void test01() {
          Person p1(18);
          cout << "p1的年齡為:" << p1.age << endl;
        }
        //2、返回對象本身用 *this
        void test02() {
          Person p1(10);
          Person p2(10);
          //鏈式編程思想
          p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);
        
          cout << "p2的年齡為:" << p2.age << endl;
        }
        
        int main()
        {
          //test01();   //示例1
        
          test02();
        
          system("pause");
          return 0;
        }
        
      空指針訪問成員函數
      • C++中空指針也是可以調用成員函數的,但是也要注意有沒有用到this指針

      • 如果用到this指針,需要加以判斷保證代碼的健壯性

      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //空指針訪問成員函數
        class Person {
        public:
          void showClassName() {
              cout << "this is Person class" << endl;
          }
          void showPersonAge() {
              //報錯原因是因為傳入的指針是為NULL
              //用if判斷指針是否為空,防止崩潰
              if (this == NULL) {
                  return;
              }
              cout << "age = " << m_Age << endl;
          }
          int m_Age;
        };
        
        void test01() {
          Person* p = NULL;
          p->showClassName();
          p->showPersonAge();  //報錯原因是因為傳入的指針是為NULL
        }
        
        int main()
        {
          //test01();   //示例1
        
          system("pause");
          return 0;
        }
        
      const修飾成員函數
      • 常函數:

        • 成員函數后加const后我們稱為這個函數為常函數
        • 常函數內不可以修改成員屬性
        • 成員屬性聲明時加關鍵字mutable后,在常函數中依然可以修改
      • 常對象:

        • 聲明對象前加const稱該對象為常對象
        • 常對象只能調用常函數
      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //常函數
        class Person {
        public:
        
          //this指針的本質,是指針常量,指針的指向是不可以修改的
          //Person * const this;
          //在成員函數后面加const,修飾的是this指向,讓指針指向的值也不可以修改
          void showPerson() const {
              this->m_B = 100;
              //this->m_A = 100;
              //this = NULL;  this指針不可以修改指針的指向的
          }
        
          void func() {
        
          }
        
          int m_A;
          mutable int m_B;  //特殊變量,即使在常函數中,也可以修改這個值,加關鍵字mutable
        };
        //常對象
        void test() {
          const Person p;   //在對象前加const,變為常對象
          //p.m_A = 100;   錯誤
          p.m_B = 100;   //m_B是特殊值,在常對象下也可以修改
        
          //常對象只能調用常函數
          p.showPerson();
          //p.func();  錯誤,因為常對象不可以調用普通成員函數,因為普通成員函數可以修改屬性
        }
        
        void test01() {
          Person p;
          p.showPerson();
        }
        int main()
        {
          //test01();   //示例1
        
          system("pause");
          return 0;
        }
        

      友元

      • 在程序里,有些私有屬性也想讓類外特殊的一些函數或者類進行訪問,就需要用到友元的技術
      • 友元的目的就是讓一個函數或者類訪問另一個類中私有成員
      • 友元的關鍵字為 friend
      • 友元的三種實現
        • 全局函數做友元
        • 類做友元
        • 成員函數做友元
      全局函數做友元
      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //建筑類
        class Building {
        
          //goodDay全局函數是Building好朋友,可以訪問Building中私有成員
          friend void goodGay(Building* building);
        public:
          Building() {
              m_SittingRoom = "客廳";
              m_BedRoom = "臥室";
          }
        public:
          string m_SittingRoom;   //客廳
        
        private:
          string m_BedRoom;   //臥室
        };
        
        //全局函數
        void goodGay(Building *building) {
          cout << "好朋友的全局函數 正在訪問:" << building->m_SittingRoom << endl;
        
          cout << "好朋友的全局函數 正在訪問:" << building->m_BedRoom << endl;
        }
        
        void test() {
          Building building;
          goodGay(&building);
        }
        
        int main()
        {
          //test01();   //示例1
        
          system("pause");
          return 0;
        }
        
      類做友元
      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //類做友元
        class Building;
        class GoodDay {
        public:
        
          GoodDay();
        
          void visit();  //參觀函數  訪問Building中的屬性
          Building* building;
        };
        
        class Building {
          friend class GoodDay;    //GoodDay類是本類的好友,可以訪問本類私有的成員
        public:
          Building();
        public:
          string m_SittingRoom;  // 客廳
        
        private:
          string m_BedRoom;  //臥室
        };
        
        //類外寫成員函數
        Building::Building() {
          m_BedRoom = "客廳";
          m_SittingRoom = "臥室";
        }
        
        GoodDay::GoodDay() {
          //創建一個建筑物對象
          building = new Building; 
        }
        
        void GoodDay::visit(){
          cout << "好友類正在訪問:" << building->m_SittingRoom << endl;
          cout << "好友類正在訪問:" << building->m_BedRoom << endl;
        }
        
        void test01() {
          GoodDay gg;
          gg.visit();
        }
        int main()
        {
          //test01();   //示例1
        
          system("pause");
          return 0;
        }
        
      成員函數做友元
      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //成員函數做友元
        class Building;
        
        class GoodDay {
        public:
          GoodDay();
        
          void visit();    //讓visit函數可以訪問Building中私有成員
          void visit2();   //讓visit2函數不可以訪問Building中私有成員
        
          Building* building;
        };
        
        class Building {
        
          //告訴編譯器  GoodDay類下的visit成員函數作為本類好友,可以訪問私有成員
          friend void GoodDay::visit();
        
        public:
          Building();
        
        public:
          string m_SittingRoom;  //客廳
        
        private:
          string m_BedRoom;  //臥室
        };
        
        //類外實現成員函數
        GoodDay::GoodDay() {
          building = new Building;
        }
        
        Building::Building() {
          m_SittingRoom = "客廳";
          m_BedRoom = "臥室";
        }
        
        void GoodDay::visit() {
          cout << "visit函數正在訪問:" << building->m_SittingRoom << endl;
          cout << "visit函數正在訪問:" << building->m_BedRoom << endl;
        }
        
        void GoodDay::visit2() {
          cout << "visit2函數正在訪問:" << building->m_SittingRoom << endl;
        }
        
        void test01() {
          GoodDay gg;
          gg.visit();
          gg.visit2();
        }
        
        int main()
        {
          //test01();   //示例1
        
          system("pause");
          return 0;
        }
        

      運算符重載

      • 運算符重載概念:對已有的運算符重新進行定義,賦予其另一種功能,以適應不同的數據類型
      加號運算符重載
      • 作用:實現兩個自定義數據類型相加的運算

      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //加號運算符重載
        class Person {
        public:
        
          //1、成員函數重載加號  +
          /*Person operator+(Person& p) {
              Person temp;
              temp.m_A = this->m_A + p.m_A;
              temp.m_B = this->m_B = p.m_B;
              return temp;
          }*/
        
          int m_A;
          int m_B;
        
        };
        
        //2、全局函數重載加號  +
        Person operator+(Person& p1, Person& p2) {
          Person temp;
          temp.m_A = p1.m_A + p2.m_A;
          temp.m_B = p1.m_B + p2.m_B;
          return temp;
        }
        
        //3、函數重載的版本
        Person operator+(Person& p1, int num) {
          Person temp;
          temp.m_A = p1.m_A + num;
          temp.m_B = p1.m_B + num;
          return temp;
        }
        
        void test01() {
          Person p1;
          p1.m_A = 10;
          p1.m_B = 10;
        
          Person p2;
          p2.m_A = 10;
          p2.m_B = 10;
        
          //成員函數重載本質調用
          /*Person p3 = p1.operator+(p2);*/
        
          //全局函數重載本質調用
          /*Person p3 = operator+(p1 , p2);*/
        
          Person p3 = p1 + p2;
        
          //運算符重載也可以發生函數重載
          Person p4 = p1 + 100;
        
          cout << "p3.m_A = " << p3.m_A << endl; 
          cout << "p3.m_B = " << p3.m_B << endl;
        
          cout << "p4.m_A = " << p4.m_A << endl;
          cout << "p4.m_B = " << p4.m_B << endl;
        }
        int main()
        {
          test01();   //示例1
        
          system("pause");
          return 0;
        }
        
        
      • 總結:

        • 1、對于內置的數據類型的表達式的運算符是不可能改變的
        • 2、不要濫用運算符重載
      左移運算符重載
      • 可以輸出自定義數據類型

      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //左移運算符重載
        
        class Person {
        
          //友元
          friend ostream& operator<<(ostream& cout, Person& p);
        
        public:
          //構造函數提供接口賦值
          Person(int a, int b) {
              m_A = a;
              m_B = b;
          }
        private:
          //利用成員函數重載 左移運算符  p.operator<<(cout)  簡化版本   p << cout
          //不會利用成員函數重載 << 運算符,因為無法實現 cout在左側
          /*void operator<<(cout) {
        
          }*/
        
          int m_A;
          int m_B;
        };
        
        //只能利用全局函數重載左移運算符
        //cout 屬于 ostream 輸出流  屬性屬于ostream  注意  operator前需要加引用符 &
        ostream & operator<<(ostream &cout , Person &p ) {   //本質 operator<<(cout,p)  簡化 cout << p
          cout << "m_A = " << p.m_A << " m_B = " << p.m_B;
          return cout;
        }
        
        void test01() {
          Person p(10,10);
          cout << p << endl;
        }
        
        int main()
        {
          test01();   //示例1
        
          system("pause");
          return 0;
        }
        
      遞增運算符重載
      • 作用:通過重載遞增運算符,實現自己的整數數據

      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //遞增運算符重載
        
        //自定義整形
        class MyInteger {
        
          //友元
          friend ostream& operator<<(ostream& cout, MyInteger myint);
        
        public:
          MyInteger() {
              m_Num = 0;
          }
        
          //重載前置++運算符  返回引用為了一直對一個數據進行遞增操作
          MyInteger & operator++() {
              //先進行++運算
              m_Num++;
              //再將自身作為返回
              return *this;
          }
          //重載后置++運算符
          // void operator++(int)里的int代表占位參數,可以用于區分前置和后置遞增
          MyInteger operator++(int) {
              //先記錄當時結果
              MyInteger temp = *this;
              //再遞增
              m_Num++;
              //最后將記錄結果做返回
              return temp;
          }
        
        private:
          int m_Num;
        };
        
        //重載<<運算符
        ostream& operator<<(ostream &cout, MyInteger myint) {
          cout << myint.m_Num;
          return cout;
        }
        
        void test01() {
          MyInteger myint;
        
          cout << ++myint << endl;
        }
        
        void test02() {
          MyInteger myint;
        
          cout << myint++ << endl;
        
          cout << myint << endl;
        
        }
        int main()
        {
          test01();   //示例1
          test02();
        
          system("pause");
          return 0;
        }
        
      賦值運算符重載
      • C++編譯器至少給一個類添加4個函數

        • 默認構造函數(無參,函數體為空)
        • 默認析構函數(無參,函數體為空)
        • 默認拷貝構造函數,對屬性進行值拷貝
        • 賦值運算符operator=,對屬性進行值拷貝
      • 如果類中有屬性指向堆區,做賦值操作時也會出現深淺拷貝

      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //賦值運算符重載
        
        class Person {
        public:
          Person(int age) {
              m_Age = new int(age);
          }
        
          ~Person() {
              if (m_Age != NULL) {
                  delete m_Age;
                  m_Age = NULL;
              }
          }
        
          //重載  賦值運算符
          Person& operator=(Person &p) {
              //編譯器是提供的淺拷貝
              //m_Age = p.m_Age;
        
              //應該先判斷時候有屬性在堆區,如果有先釋放干凈,然后再深拷貝
              if (m_Age != NULL) {
                  delete m_Age;
                  m_Age = NULL;
              }
              //深拷貝操作 
              m_Age = new int(*p.m_Age);
        
              //返回對象本身
              return *this;
          }
        
          int* m_Age;
        };
        
        void test01() {
          Person p1(18);
          Person p2(20);
        
          p2 = p1;   //賦值操作
        
          cout << "p1的年齡為:" << p1.m_Age << endl;
          cout << "p2的年齡為:" << p2.m_Age << endl;
        }
        
        int main()
        {
          test01();   //示例1
          test02(); 
        
          system("pause");
          return 0;
        }
        
      關系運算符重載
      • 作用:重載關系運算符,可以讓兩個自定義類型對象進行對比操作

      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //重載關系運算符
        class Person {
        public:
          Person(string name, int age) {
              m_Name = name;
              m_Age = age;
          }
        
          //重載 == 號關系運算符
          bool operator==(Person &p) {
              if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) {
                  return true;
              }
              return false;
          }
        
          //重載 !=號關系運算符
          bool operator!=(Person &p) {
              if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) {
                  return false;
              }
              return true;
          }
        
          string m_Name;
          int m_Age;
        };
        
        void test01() {
          Person p1("Tom", 18);
          Person p2("Tom", 18);
          if (p1 == p2) {
              cout << "p1和p2相同" << endl;
          }
        }
        
        int main()
        {
          test01();   //示例1
        
          system("pause");
          return 0;
        }
        
      函數調用運算符重載
      • 函數調用運算符()也可以重載

      • 由于重載后使用的方式非常像函數的調用,因此稱為仿函數

      • 仿函數沒有固定寫法,非常靈活

      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //函數調用運算符重載
        class MyPrint {
        public:
        
          //重載函數調用運算符
          void operator()(string text) {
              cout << text << endl;
         }
        };
        
        void test01() {
          MyPrint myPrint;
          myPrint("hello world");  //由于使用起來非常類似于函數調用,因此稱為仿函數
        }
        
        //仿函數非常靈活,沒有固定的寫法
        //加法
        
        class MyAdd {
        public:
          int operator()(int num1, int num2) {
              return num1 + num2;
          }
        };
        
        void test02() {
          MyAdd myadd;
          int ret = myadd(100, 100);
          cout << "ret = " << ret << endl;
        
          //匿名函數對象
          cout << MyAdd()(100, 100) << endl;
        }
        
        int main()
        {
          test01();   //示例1
          test02();
        
          system("pause");
          return 0;
        }
        

      繼承

      • 繼承是面向對象三大特性之一
      • 繼承的技術可以減少重復代碼
      集成的基本語法
      • 基本語法:class 子類 : 繼承方式 父類 {...};
      • class A : public B {...};
      • A:子類:稱為派生類
      • B:父類:稱為基類
      繼承方式
      • 繼承方式一共有三種:

        • 公共繼承
        • 保護繼承
        • 私有繼承
      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //繼承方式
        class Basel {
        public:
          int m_A;
        protected:
          int m_B;
        private:
          int m_C;
        };
        
        //公共繼承
        class Son1 :public Basel {
        public:
          void func() {
              //父類中的公關權限成員 到子類中依然是公共權限
              m_A = 10;  
              //父類中的保護權限成員 到子類中依然是保護權限
              m_B = 10;
              //父類中的私有權限成員 子類訪問不到
              //m_C = 10;
          }
        };
        
        //保護繼承
        class Son2 :protected Basel {
        public:
          void func() {
              //父類中的公共成員,到子類中變為保護權限
              m_A = 100;
              //父類中保護成員,到子類中變為保護權限
              m_B = 100;
        
              //父類中的私有成員 子類訪問不到
              //m_C = 100;
          }
        };
        
        //私有繼承
        class Son3 :private Basel {
        public:
          void func() {
              //父類中公共成員 到子類中變為私有成員
              m_A = 100;
              //父類中保護乘員 到子類中變為私有成員
              m_B = 100;
        
              //父類中私有的成員,子類訪問不到
              //m_C = 100;
          }
        };
        
        class GrandSon3 :public Son3 {
        public:
          void func() {
              //到了Son3中 m_A變為私有  此子類也訪問不到
              //m_A = 1000;
              // 到了Son3中 m_B變為私有  此子類也訪問不到
              //m_B = 1000;
          }
        };
        
        void test01() {
          Son1 s1;
          s1.m_A = 100;
        
          //到Son1中 m_B是保護權限  類外訪問不到
          //s1.m_B = 10;
        }
        
        void test02() {
          Son2 s2;
          //s1.m_A = 1000;     在Son2中 m_A變為保護權限,因此類外訪問不到
          //是。m_B = 1000;   在Son2中 m_B保護權限  類外不可以訪問
        }
        
        void test03() {
          Son3 s3;
        
          //s3.m_A = 100;   在Son3中 m_A變為私有成員  類外訪問不到
          //s3.m_B = 100;   在Son3中 m_B變為私有成員  類外訪問不到
        }
        
        int main()
        {
          test01();   //示例1
          test02();
        
          system("pause");
          return 0;
        }
        
      繼承中的對象模型
      • 問題:從父類繼承過來的成員,哪些屬于子類對象中的

      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //繼承中的對象模型
        class Base {
        public:
          int m_A;
        protected:
          int m_B;
        private:
          int m_C;
        };
        
        class Son :public Base {
        public:
          int m_D;
        };
        
        void test01() {
        
          //父類中所有非靜態成員屬性都會被子類繼承下去
          //父類中私有成員屬性 是被編譯器給隱藏了 因此訪問不到 但是確實被繼承下去了
          //可在vs 開發人員命令提示符里查看對象模型  cd到具體的文件路徑下
          //命令 cl /d1 reportSingleClassLayout"類名" "文件命"  “tab補全”  (第一個是L第二個是數字1)
          cout << "size of Son = " << sizeof(Son) << endl;   //16
        }
        
        int main()
        {
          test01();   //示例1
         
          system("pause");
          return 0;
        }
        
        
      繼承中構造和析構順序
      • 子類繼承父類后,當創建子類對象,也會調用父類的構造函數

      • 父類和子類的構造和析構順序

      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //繼承中的構造和析構的順序
        class Base {
        public:
          Base() {
              cout << "Base構造函數" << endl;
          }
        
          ~Base() {
              cout << "Base析構函數" << endl;
          }
        };
        
        class Son :public Base {
        public:
          Son() {
              cout << "Son構造函數" << endl;
          }
        
          ~Son() {
              cout << "Son析構函數" << endl;
          }
        };
        
        void test01() {
          //Base b;
          //繼承中的構造和析構順序如下:
          //先構造父類,再構造子類  析構的順序與構造的順序相反
          Son s;
        }
        
        int main()
        {
          test01();   //示例1
         
          system("pause");
          return 0;
        }
        
      繼承同名成員處理方式
      • 當子類與父類出現同名的成員,通過子類對象訪問子類與父類同名的數據方法:

        • 訪問子類同名成員直接訪問即可
        • 訪問父類同名成員需要加作用域
      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //繼承同名成員處理方式
        class Base {
        public:
          Base() {
              m_A = 100;
          }
        
          void func() {
              cout << "Base - func()調用" << endl;
          }
        
          void func(int a) {
              cout << "Base - func(int a)調用" << endl;
          }
        
          int m_A;
        };
        
        class Son :public Base {
        public:
          Son() {
              m_A = 200;
          }
        
          void func() {
              cout << "Son - func()調用" << endl;
          }
        
          int m_A;
        };
        
        //同名成員屬性處理方式
        void test01() {
          Son s;
          cout << "Son m_A = " << s.m_A << endl;
        
          //如果通過子類對象訪問父類中同名成員需要加作用域
          cout << "Base m_A = " << s.Base::m_A << endl;
        }
        
        //同名成員函數處理方式
        void test02() {
          Son s;
          s.func();  //直接調用  調用是子類中的同名成員
        
          //調用父類中同名成員函數
          s.Base::func();
        
          //如果子類中出現和父類同名的成員函數,子類的同名成員會隱藏掉父類中所有同名成員函數
          //如果想訪問到父類中被隱藏的同名成員函數,需要加作用域
          //s.func(100);  報錯
          s.Base::func(100);
        }
        
        int main()
        {
          test01();   //示例1
          test02();
        
          system("pause");
          return 0;
        }
        
      繼承同名靜態成員處理方式
      • 繼承中同名的靜態成員在子類對象上與非靜態成員處理方式一致

        • 訪問子類同名成員 直接訪問即可
        • 訪問父類同名成員 需要加作用域
      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //繼承同名靜態成員處理方式
        class Base {
        public:
          static void func() {
              cout << "Base - staitc void func()" << endl;
          }
        
          static void func(int a) {
              cout << "Base - staitc void func(int a)" << endl;
          }
          static int m_A;
        };
        
        int Base::m_A = 100;
        
        class Son :public Base {
        public:
          static int m_A;
          static void func() {
              cout << "Son - staitc void func()" << endl;
          }
          static int m_A;
        };
        int Son::m_A = 200;
        
        //同名靜態成員屬性處理方式
        void test01() {
        
          //1、通過對象訪問
          cout << "通過對象訪問:" << endl;
          Son s;
          cout << "Son m_A = " << s.m_A << endl;
          cout << "Base m_A = " << s.Base::m_A << endl;
        
          //2、通過類名訪問
          cout << "通過類名訪問:" << endl;
          cout << "Son m_A = " << Son::m_A << endl;
          //第一個:: 代表通過類名方式訪問  第二個::代表訪問父類作用域下
          cout << "Base m_A = " << Son::Base::m_A << endl;
        
        }
        
        //同名靜態成員函數處理方式
        void test02() {
          //1、通過對象訪問
          cout << "通過對象訪問:" << endl;
          Son s;
          s.func();
          s.Base::func();
        
          //通過類名訪問
          cout << "通過類名訪問:" << endl;
          Son::func();
          Son::Base::func();
        
          //子類出現和父類同名靜態成員函數,也會隱藏父類中所有同名成員函數
          //如果想訪問父類中被隱藏同名成員,需要加作用域
          Son::Base::func(100);
        }
        
        int main()
        {
          test01();   //示例1
          test02();
        
          system("pause");
          return 0;
        }
        
      多繼承語法
      • C++允許一個類繼承多個類

      • 語法:class 子類:繼承方式 父類1, 繼承方式 父類2...

      • 多繼承可能會引發父類中有同名成員出現,需要加作用域區分

      • 注意:C++實際開發中不建議用多繼承

      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //多繼承語法
        class Base {
        public:
          Base() {
              m_A = 100;
          }
           int m_A;
        };
        
        class Base2 {
        public:
          Base2() {
              m_A = 100;
          }
          int m_A;
        };
        
        //子類 需要繼承Base和Base2
        //語法:class 子類 :繼承方式 父類1, 繼承方式 父類2 ...
        class Son :public Base , public Base2 {
        public:
          Son() {
              m_C = 300;
              m_D = 400;
          }
          int m_C;
          int m_D;
        };
        
        void test01() {
          Son s;
          cout << "sizeof Son = " << sizeof(s) << endl;
        
          //當父類中出現同名成員,需要加作用域區分
          cout << "Base m_A = " << s.Base::m_A << endl;
          cout << "Base2 m_A = " << s.Base2::m_A << endl;
          }
        
        int main()
        {
          test01();   //示例1
          
          system("pause");
          return 0;
        }
        
      菱形繼承
      • 菱形繼承概念:

        • 兩個派生類繼承同一個基類
        • 又有某個類同時繼承這兩個派生類
        • 菱形繼承也成為鉆石繼承
      • 菱形繼承問題:

        • 當兩個派生類同時繼承基類,繼承這兩個派生類的新類使用數據時,就會產生二義性
        • 新類繼承基類的數據繼承了兩份,這份數據中只需要一份就可以
      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //動物類
        class Animal {
        public:
          int m_Age;
        };
        
        //利用虛繼承 解決菱形繼承的問題
        // 繼承之前  加上關鍵字 virtual 變為虛繼承
        // Animal類稱為 虛基類
        //羊類
        class Sheep :virtual public Animal {
        
        };
        
        //駝類
        class Tuo :virtual public Animal {
        
        };
        
        //羊駝類
        class SheeoTuo :public Sheep, public Tuo {
        
        };
        
        void test01() {
          SheeoTuo st;
          st.Sheep::m_Age = 18;
          st.Tuo::m_Age = 28;
          //當出現菱形繼承,有兩份父類擁有相同的數據,需要加以作用域區分
          cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl;
          cout << "st.Tuo::m_Age = " << st.Tuo::m_Age << endl;
          cout << "st.m_Age = " << st.m_Age << endl;
        
          //這份數據知道只要有一份就可以了,菱形繼承導致了數據有兩份,資源浪費
        
        }
        
        //虛繼承
        //vbptr  ---- vbtable   指向虛基類表
        //v - virtual  虛
        //b - base  基類
        //ptr - pointer 指針
        
        int main()
        {
          test01();   //示例1
          
          system("pause");
          return 0;
        }
        

      多態

      多態的基本概念
      • 多態是C++面向對象三大特性之一

      • 多態分為兩類

        • 靜態多態:函數重載和運算符重載屬于靜態多態,復用函數名
        • 動態多態:派生類和虛函數實現運行時多態
      • 靜態多態和動態多態區別:

        • 靜態多態的函數地址早綁定 - 編譯階段確定函數地址
        • 動態多態的函數地址晚綁定 - 運行階段確定函數地址
      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //多態
        
        //動物類
        class Animal {
        public:
          //speak函數就是虛函數
          //函數前面加上virtual關鍵字,變成虛函數,那么編譯器在編譯的時候就不能確定函數調用了
          virtual void speak() {
              cout << "動物再說話" << endl;
         }
        };
        
        //貓類
        class Cat :public Animal {
        public:
          //重寫  函數返回值類型  函數名稱  參數列表  完全相同
          void speak() {
              cout << "小貓在說話" << endl;
          }
        };
        
        //狗類
        class Dog :public Animal {
        public:
          void speak() {
              cout << "小狗在說話" << endl;
          }
        };
        
        //執行說話的函數
        //地址早綁定  在編譯階段就確定函數地址
        /如果想執行讓貓說話,那么這個函數地址就不能提前綁定,需要在執行階段進行綁定,地址晚綁定
        
        //動態多態滿足條件
        //1、有繼承關系
        //2、子類要重寫父類的虛函數
        
        //動態多態使用
        //父類的指針或者引用 指向子類對象
        
        //我們希望傳入什么對象,那么久調用什么對象的函數
        //如果函數地址在編譯階段就能確定,就是靜態聯編
        //如果函數地址在運行階段才能確定,就是動態聯編
        
        void doSpeak(Animal& animal) {    //Animal & animal =  cat;
          animal.speak();               //動物在說話
        }
        
        void test01() {
          Cat cat;
          doSpeak(cat);
        
          Dog dog;
          doSpeak(dog);
        }
        
        int main()
        {
          test01();   //示例1
          
          system("pause");
          return 0;
        }
        
      多態案例---計算器類
      • 多態的優點

        • 代碼組織結構清晰
        • 可讀性強
        • 利于后期和前期的擴展以及維護
      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        ////分別利用普通寫法和多態技術實現計算器
        
        //普通寫法
        class Calculator {
        public:
        
          int getRestlt(string oper) {
              if (oper == "+") {
                  return m_Num1 + m_Num2;
              }
              else if (oper == "-") {
                  return m_Num1 - m_Num2;
              }
              else if (oper == "*") {
                  return m_Num1 * m_Num2;
              }
              else if (oper == "/") {
                  return m_Num1 / m_Num2;
              }
        
          //如果想擴展新的功能,需要修改源碼
          //在正式開發環境中,提倡開閉原則
          //在開閉原則:對擴展進行開放,對修改進行關閉44
        
          }
        
          int m_Num1;  //操作數 1 
          int m_Num2;  //操作數 2
        };
        
        void test01() {
        
          //創建計算器對象
          Calculator c;
          c.m_Num1 = 10;
          c.m_Num2 = 10;
          
          cout << c.m_Num1 << " + " << c.m_Num2 << " = " << c.getRestlt("+") << endl;
        }
        
        //利用多態實現計算器
        //多態好處:
        // 1、組織結構清晰
        // 2、可讀性強
        // 3、對于前期和后期擴展以及維護性高
        //實現計算器抽象類
        class AbstractCalculator {
        public:
        
          virtual int getResult() {
              return 0;;
          }
        
          int m_Num1;
          int m_Num2;
        };
        
        //加法計算器類
        class addCalculator :public AbstractCalculator {
        public:
          int getResult() {
              return m_Num1 + m_Num2;
          }
        };
        
        //減法計算器類
        class SubCalculator :public AbstractCalculator {
        public:
          int getResult() {
              return m_Num1 - m_Num2;
          }
        };
        
        //乘法計算器類
        class MulCalculator :public AbstractCalculator {
        public:
          int getResult() {
              return m_Num1 * m_Num2;
          }
        };
        
        void test02() {
          //多態使用條件
          //父類指針或者引用指向子類對象
        
          //加法運算
          AbstractCalculator* abc = new addCalculator;
          abc->m_Num1 = 10;
          abc->m_Num2 = 10;
        
          cout << abc->m_Num1 << " + " << abc->m_Num2 << " = " << abc->getResult() << endl;
          delete abc;
        
          //減法運算
          abc = new SubCalculator;
          abc->m_Num1 = 100;
          abc->m_Num2 = 10;
          cout << abc->m_Num1 << " - " << abc->m_Num2 << " = " << abc->getResult() << endl;
          delete abc;
        }
        
        int main()
        {
          test01();   //示例1
          test02();   //示例2
          system("pause");
          return 0;
        }
        
      • 總結:C++開發提倡利用多態設計程序架構,因為多態優點很多

      純虛函數和抽象類
      • 在多態中,通常父類中虛函數的實現是毫無意義的,主要都是調用子類重寫的內容,因此可將虛函數改為純虛函數

      • 純虛函數語法:virtual 返回值類型 函數名 (參數列表) = 0;

      • 當類中有了純虛函數,這個類也成為抽象類

      • 抽象類特點:

        • 無法實例化對象
        • 子類必須重寫抽象類中的純虛函數,否則也屬于抽象類
      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //純虛函數和抽象類
        
        class Base {
        public:
          //純虛函數
          //只要有一個純虛函數,這個類稱為抽象類
          //抽象類特點:
          //1、無法實例化對象
          //2、抽象類的子類必須要重寫父類中的純虛函數,否則也屬于抽象類
          virtual void func() = 0;
        };
        
        class Son :public Base {
        public:
          virtual void func() {
              cout << "func函數調用" << endl;
          }
        };
        
        void test01() {
          //Base b;//抽象類是無法實例化對象的
          //new Base;抽象類是無法實例化對象的
        
          //Son s;  //子類必須重寫父類中的純虛函數,否則無法實例化對象
        
          Base* base = new Son;
          base->func();
          delete base; //記得銷毀
        }
        
        void test02() {
        
        }
        
        int main()
        {
          test01();   //示例1
          
          system("pause");
          return 0;
        }
        
      多態案例---制作飲品
      • 案例描述:

        • 流程:煮水、沖泡、倒入杯中-加入輔料
        • 利用多態技術實現,提供抽象制作飲品基類,提供子類制作咖啡和茶葉
      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //多態案例2   制作飲品
        
        class AbstractDrinking {
        public:
        
          //煮水
          virtual void Boil() = 0;
        
          //沖泡
          virtual void Brew() = 0;
        
          //倒入杯中
          virtual void PourInCup() = 0;
        
          //加入輔料
          virtual void PutSomething() = 0;
        
          //制作飲品
          void makeDrink() {
              Boil();
              Brew();
              PourInCup();
              PutSomething();
          }
        };
        
        //制作咖啡
        class Coffee :public AbstractDrinking {
        public:
          //煮水
          virtual void Boil() {
              cout << "煮農夫山泉" << endl;
          }
        
          //沖泡
          virtual void Brew() {
              cout << "沖泡咖啡" << endl;
          }
        
          //倒入杯中
          virtual void PourInCup() {
              cout << "倒入杯中" << endl;
          }
        
          //加入輔料
          virtual void PutSomething() {
              cout << "加入糖和牛奶" << endl;
          }
        };
        
        //制作茶水
        class Tea :public AbstractDrinking {
        public:
          //煮水
          virtual void Boil() {
              cout << "煮農夫山泉" << endl;
          }
        
          //沖泡
          virtual void Brew() {
              cout << "沖泡茶葉" << endl;
          }
        
          //倒入杯中
          virtual void PourInCup() {
              cout << "倒入杯中" << endl;
          }
        
          //加入輔料
          virtual void PutSomething() {
              cout << "加入檸檬" << endl;
          }
        };
        
        //制作的函數
        void doWork(AbstractDrinking* abs) {  //AbstractDrinking * abs = new Coffee
          abs->makeDrink();
          delete abs;  //手動釋放
        
        }
        
        void test01() {
          //制作咖啡
          doWork(new Coffee);
        
          cout << "--------------------------" << endl;
        
          //制作茶葉
          doWork(new Tea);
        }
        
        void test02() {
        
        }
        
        int main()
        {
          test01();   //示例1
          
          system("pause");
          return 0;
        }
        
      虛析構和純虛析構
      • 多態使用時,如果子類中有屬性開辟到堆區,那么父類指針在釋放時無法調用到子類的析構代碼

      • 解決方式:將父類中的析構函數改為虛析構或者純虛析構

      • 虛析構額純虛析構共性:

        • 可以解決父類指針釋放子類對象
        • 都需要有具體的函數實現
      • 虛析構和純虛析構區別

        • 如果是純虛析構,該類屬于抽象類,無法實例化對象
      • 虛析構語法

        • virtual ~類名(){}
      • 純虛析構語法

        • virtual ~類名() = 0;
        • 類名::~類名(){}
      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        
        //虛析構和純虛析構
        
        class Animal {
        public:
        
          Animal() {
              cout << "Animal構造函數調用" << endl;
          }
        
          //利用虛析構可以解決父類指針釋放子類對象時不干凈的問題
          /*virtual ~Animal() {
              cout << "Animal虛析構函數調用" << endl;
          }*/
        
          //純虛析構  需要聲明也需要實現
          //有了純虛析構之后,這個類也屬于抽象類,無法實例化對象
          virtual ~Animal() = 0;
        
          //純虛函數
          virtual void speak() = 0;
        
        };
        
        Animal::~Animal() {
          cout << "Animal純虛析構函數調用" << endl;
        }
        
        class Cat :public Animal {
        public:
        
          Cat(string name) {
        
              cout << "Cat構造函數調用" << endl;
              m_Name = new string(name);
          }
        
          virtual void speak() {
              cout << *m_Name << "小貓在說話" << endl;
          }
          
          ~Cat() {
              if (m_Name != NULL) {
        
                  cout << "Cat析構函數調用" << endl;
                  delete m_Name;
                  m_Name = NULL;
              }
          }
        
          string* m_Name;
        };
        
        void test01() {
          Animal* animal = new Cat("Tom");
          animal->speak();
          //父類指針在析構時候,不會調用子類中析構函數,導致子類如果有堆區屬性,出現內存泄露
          delete animal;
        }
        
        void test02() {
        
        }
        
        int main()
        {
          test01();   //示例1
          
          system("pause");
          return 0;
        }
        
      • 總結:

        • 1、虛析構或純虛析構就是用來解決通過父類指針釋放子類對象
        • 2、如果子類中沒有堆區數據,可以不寫為虛析構或純虛析構
        • 3、擁有純虛析構函數的類也屬于抽象類

      文件操作

      • 通過文件可以將數據持久化
      • C++中對文件操作需要包含頭文件
      • 文件類型分為兩種
        • 文本文件:文件以文本的ASCII碼形式存儲在計算機中
        • 二進制文件“文件以文本的二進制形式存儲在計算機中,用戶一般不能直接讀懂它們
      • 操作文件的三大類
        • ofstream:寫操作
        • ifstream:讀操作
        • fstream:讀寫操作

      文本文件

      寫文件
      • 寫文件步驟如下:
        • 包含頭文件
          • include

        • 創建流對象
          • ofstream ofs;
        • 打開文件
          • ofs.open("文件路徑",打開方式);
        • 寫數據
          • ofs <<"寫入數據";
        • 關閉文件
          • ofs.close();
      • 文件打開方式:
      打開方式 釋義
      ios::in 為讀文件而打開文件
      ios::out 為寫文件而打開文件
      ios::ate 初始位置:文件尾
      ios::app 追加方式寫文件
      ios::trunc 如果文件存在先刪除再創建
      ios::binary 二進制方式
      • 注意:文件打開方式可以配合使用,利用|操作符

      • 例如:用二進制方式寫文件 iso::binary | ios::out 二進制方式寫文件

      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        #include <fstream>
        
        //文本文件  寫文件
        
        void test01() {
          
          //1、包含頭文件fstream
        
          //2、創建流對象
        
          ofstream ofs;
        
          //3、指定打開方式
        
          ofs.open("test.txt", ios::out);
        
          //4、寫內容
        
          ofs << "姓名:張三" << endl;
          ofs << "性別:男" << endl;
        
          //5、關閉文件
          ofs.close();
        }
        
        void test02() {
        
        }
        
        int main()
        {
          test01();   //示例1
          
          system("pause");
          return 0;
        }
        
      讀文件
      • 讀文件步驟:

        • 包含頭文件
          • include

        • 創建流對象
          • ifstream ifs;
        • 打開文件并判斷文件是否打開成功
          • ifs.open("文件路徑",打開方式);
        • 讀數據
          • 四種方式讀取
        • 關閉文件
          • ifs.close();
      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        #include <fstream>
        
        //文本文件  讀文件
        
        void test01() {
          
          //1、包含頭文件fstream
        
          //2、創建流對象
        
          ifstream ifs;
        
          //3、指定打開方式
        
          ifs.open("test.txt", ios::in);
        
          if (!ifs.is_open()) {
              cout << "文件打開失敗" << endl;
              return;
          }
        
          //4、讀數據
          //第一種
          /*char buf[1024] = { 0 };
          while (ifs >> buf) {
              cout << buf << endl;
          }*/
        
          //第二種
          /*char buf[1024] = { 0 };
          while (ifs.getline(buf,sizeof(buf)))
          {
              cout << buf << endl;
          }*/
        
          //第三種
          string buf;
          while (getline(ifs,buf))
          {
              cout << buf << endl;
          }
        
          //第四種
          //char c;
          //while ((c=ifs.get())!=EOF)   //EOF end of file
          //{
          //    cout << c;
          //}
        
          //5、關閉文件
          ifs.close();
        }
        
        void test02() {
        
        }
        
        int main()
        {
          test01();   //示例1
          
          system("pause");
          return 0;
        }
        

      二進制

      • 以二進制的方式對文件進行讀寫操作
      • 打開方式要指定為 ios::binary
      寫文件
      • 二進制方式寫文件主要利用流對象調用成員數write

      • 函數原型:ostream& write(const char * buffer,int len);

      • 參數解釋:字符指針buffer指向內存種一段存儲空間。len是讀寫的字節數

      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        #include <fstream>
        
        //二進制文件  寫文件
        
        class Person {
        public:
          char m_Name[64];  //姓名
          int m_Age;  //年齡
        };
        
        void test01() {
          
          //1、包含頭文件fstream
        
          //2、創建流對象
        
          ofstream ofs("Person.txt", ios::out | ios::binary);
        
          //3、指定打開方式
          //ofs.open("Person.txt", ios::out | ios::binary);
          
          //4、寫數據
          Person p = { "張三",18 };
          ofs.write((const char *)&p,sizeof(Person));
        
          //5、關閉文件
          ofs.close();
        }
        
        void test02() {
        
        }
        
        int main()
        {
          test01();   //示例1
          
          system("pause");
          return 0;
        }
        
      讀文件
      • 二進制方式讀文件主要利用流對象調用成員函數read

      • 函數原型:istream& read(char * buffer,int len);

      • 參數解釋:字符指向buffer指向內存中一段存儲空間。len是讀寫的字節數

      • 示例:

        #include <iostream>
        using namespace std;
        #include <string>
        #include <fstream>
        
        //二進制文件  讀文件
        
        class Person {
        public:
          char m_Name[64];  //姓名
          int m_Age;  //年齡
        };
        
        void test01() {
          
          //1、包含頭文件fstream
        
          //2、創建流對象
        
          ifstream ifs;
        
          //3、指定打開方式
          ifs.open("Person.txt", ios::in | ios::binary);
        
          if (ifs.is_open()) {
              cout << "文件打開失敗" << endl;
              return;
          }
          
          //4、讀數據
          Person p;
          ifs.read((char*)&p, sizeof(Person));
          cout << "姓名:" << p.m_Name << " 年齡:" << p.m_Age << endl;
        
          //5、關閉文件
          ifs.close();
        }
        
        oid test02() {
        
        }
        
        int main()
        {
          test01();   //示例1
          
          system("pause");
          return 0;
        }
        

      C++提高編程

      • C++泛型編程和STL技術

      模板

      模板的概念

      • 作用:建立通用的模具,大大提高復用性
      • 特點:
        • 模板不可以直接使用,它只是一個框架
        • 模板的通用并不是萬能的

      函數模板

      • C++另一種編程思想稱為泛型編程,主要利用的技術就是模板
      • C++提供兩種模板機制:【函數模板】和【類模板】
      函數模板語法
      • 函數模板作用:

        • 建立一個通用函數,其函數返回值類型和形參類型可以不具體制定,用一個虛擬的類型來代表
      • 語法:

        template<typename T>
        //函數聲明或定義
        
      • 釋義:

        • template --- 聲明創建模板
        • typename --- 表示其后面的符號是一種數據類型,可以用class代替
        • T --- 通用的數據類型,名稱可以替換,通常為大寫字母
      • 示例:

        #include<iostream>
        using namespace std;
        
        //函數模板
        //交換兩個整型函數
        void swapInt(int& a, int& b)
        {
        int temp = a;
        a = b;
        b = temp;
        }
        
        //交換兩個浮點型函數
        void swapDouble(double& a, double& b)
        {
        double temp = a;
        a = b;
        b = temp;
        }
        
        //函數模板
        //聲明一個模板,告訴編譯器后面代碼中緊跟著的【T】不要報錯,【T】是一個通用數據類型
        template<typename T>  //【typename】可以替換成class
        //通用交換函數
        void mySwap(T& a, T& b)
        {
        T temp = a;
        a = b;
        b = temp;
        }
        

        //測試
        void test01()
        {
        int a = 10;
        int b = 20;

        //swapInt(a, b);
        //利用函數模板交換
        //兩種方式使用函數模板

        //1、自動類型推到
        //mySwap(a, b);

        //2、顯示指定類型
        mySwap(a,b);

        cout << "a = " << a << endl;
        cout << "b = " << b << endl;

        //double c = 1.1;
        //double d = 2.2;
        //swapDouble(c, d);
        //cout << "c = " << c << endl;
        //cout << "d = " << d << endl;

        }

        int main()
        {
        //測試
        test01();

        system("pause");
        return 0;

        }

      • 總結:

        • 函數模板利用關鍵字【template】
        • 使用函數模板有兩種方式:
          • 自動類型推導
          • 顯式指定類型
        • 模板的目的是為了提高復用性,講類型參數化
      函數模板注意事項
      • 注意事項
        • 自動類型推導,必須推導出一致的數據類型T才可以使用
        • 模板必須要確定處T的數據類型,才可以使用
      • 示例
        #include<iostream>
        using namespace std;
        
        //函數模板
        //聲明一個模板,告訴編譯器后面代碼中緊跟著的【T】不要報錯,【T】是一個通用數據類型
        template<typename T>  //【typename】可以替換成class
        //通用交換函數
        void mySwap(T& a, T& b)
        {
          T temp = a;
          a = b;
          b = temp;
        }
        
        //函數模板注意事項
        //1、自動類型推導,必須推導出一致的數據類型T才可以使用
        void test01()
        {
          int a = 10;
          int b = 20;
          mySwap(a, b);  //正確
        
          char c = 'c';
          //mySwap(a, c); // 錯誤!推到不出一致的T類型
        
          cout << "a = " << a << endl;
          cout << "b = " << b << endl;
        }
        
        //2、模板必須要確定處T的數據類型,才可以使用
        template<typename T>
        void func()
        {
          cout << "func 調用";
        }
        
        void test02()
        {
          //func();    //錯誤,模板不能獨立使用,必須確定出【T】的類型
          func<int>(); //利用顯示指定類型的方式,給T一個類型,才可以使用該模板
        }
        
        int main()
        {
          //測試
          test01();
        
          system("pause");
          return 0;
        }
        
      案例
      • 案例描述

        • 利用函數模板封裝一個排序的函數,可以對不同數據類型數組進行排序
        • 排序規則從小到大,排序算法為選擇排序
        • 分別利用char數組和int數組進行測試
      • 示例:

        #include<iostream>
        using namespace std;
        
        //實現通用 對數組進行排序的函數
        //規則 從大到小
        //算法 選擇
        //測試 char數組、int數組
        
        //交換函數模板
        template<typename T>
        void mySwap(T& a, T& b)
        {
        T temp = a;
        a = b;
        b = temp;
        }
        
        //排序算法
        template<typename T>
        void mySort(T arr[],int len)
        {
        for (int i = 0; i < len; i++)
        {
        	int max = i; //認定最大值的下標
        	for (int j = i + 1; j < len; j++)
        	{
        		//認定的最大值比遍歷出的數值要小,說明【j】下標的元素才是真正的最大值
        		if (arr[max] < arr[j])
        		{
        			max = j;//更新最大值下標
        		}
        	}
        	if (max != i)
        	{
        		//交換【max】和【i】下標元素
        		mySwap(arr[i], arr[max]);
        	}
        }
        }
        
        //提供打印數組模板
        template<typename T>
        void printArray(T arr[], int len)
        {
        for (int i = 0; i < len; i++)
        {
        	cout << arr[i] << " ";
        }
        cout << endl;
        }
        
        //測試
        void test01()
        {
        //測試char數組
        char charArr[] = "badcfe";
        
        //計算數組長度
        int num = sizeof(charArr) / (sizeof(char));
        
        //傳入排序函數模板參數
        mySort(charArr, num);
        //傳入打印函數模板參數
        printArray(charArr,num);
        }
        
        void test02()
        {
        //測試int數組
        int intArr[] = { 7,5,1,3,9,2,4,6,8 };
        //計算數組長度
        int num = sizeof(intArr) / (sizeof(int));
        
        //傳入排序函數模板參數
        mySort(intArr, num);
        //傳入打印函數模板參數
        printArray(intArr, num);
        }
        
        int main()
        {
        //測試
        test01();
        
        test02();
        
        system("pause");
        return 0;
        }
        
      普通函數與函數模板的區別
      • 區別:

        • 普通函數調用時可以發生自動類型轉換(隱式類型轉換)
        • 函數模板調用時,如果利用自動類型推導,不會發生隱式類型轉換
        • 如果利用顯示指定類型的方式,可以發生隱式類型轉換
      • 示例:

        #include<iostream>
        using namespace std;
        
        //普通函數與函數模板區別
        
        //1、普通函數調用可以發生隱式類型轉換
        
        //2、函數模板 用自動類型推導,不可以發生隱式類型轉換
        
        //3、函數模板 用顯示指定類型,可以發生隱式類型轉換
        
        //普通函數
        int myAdd01(int a, int b)
        {
        return a + b;
        }
        
        //函數模板
        template<typename T>
        T myAdd02(T a, T b)
        {
        return a + b;
        }
        
        //測試
        void test01()
        {
        int a = 10;
        int b = 20;
        
        char c = 'c';
        //區別 1
        cout << myAdd01(a, c) << endl;
        
        //自動類型推導  不可以發生隱式類型轉換
        //cout << myAdd02(a, c) << endl;;
        
        //顯示指定類型  可以發生隱式類型轉換
        cout << myAdd02<int>(a, c) << endl;
        }
        
        int main()
        {
        //測試
        test01();
        
        system("pause");
        return 0;
        }
        
      普通函數與函數模板的調用規則
      • 調用規則如下:

        • 如果函數模板和普通函數都可以實現,優先調用普通函數
        • 可以通過空模板參數列表來強制調用函數模板
        • 函數模板也可以發生重載
        • 如果函數模板可以產生更好的匹配,優先調用函數模板
      • 示例:

        #include<iostream>
        using namespace std;
        
        //普通函數與函數模板調用規則
        //1、如果函數模板和普通函數都可以實現,優先調用普通函數
        //2、可以通過空模板參數列表來強制調用函數模板
        //3、函數模板也可以發生重載
        //4、如果函數模板可以產生更好的匹配,優先調用函數模板
        
        void myPrint(int a, int b)
        {
          cout << "調用的普通函數" << endl;
        }
        
        template<typename T>
        void myPrint(T a, T b)
        {
          cout << "調用的模板函數" << endl;
        }
        
        template<typename T>
        void myPrint(T a, T b, T c)
        {
          cout << "調用的模板函數" << endl;
        }
        
        //測試
        void test01()
        {
          int a = 10;
          int b = 20;
          int c = 30;
        
          //1、如果函數模板和普通函數都可以實現,優先調用普通函數
          //myPrint(a, b);
        
          //2、通過空模板參數列表來強制調用函數模板
          //myPrint<>(a, b);
        
          //3、函數模板也可以發生重載
          //myPrint(a, b, c);
        
          //4、如果函數模板可以產生更好的匹配,優先調用函數模板
          char c1 = 'a';
          char c2 = 'b';
          myPrint(c1, c2);
        }
        
        int main()
        {
          //測試
          test01();
        
          system("pause");
          return 0;
        }
        
      模板的局限性
      • 局限性

        • 模板的通用性并不是萬能的
      • 例如:

        template<typename T>
        void f(T a,T b)
        {
          a = b;
        }
        
      • 上述代碼中提供的賦值操作,如果傳入的a和b是一個數組,就無法實現

      • 例如:

        template<typename T>
        void f(T a,T b)
        {
          if(a > b)
          {
            ...
          }
        }
        
      • 如果T的數據類型傳入的是像Person這樣的自定義數據類型,也無法正常運行

      • C++為了解決這種問題,提供模板的重載,可以為這些特定的類型提供具體化的模板

      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        
        //模板局限性
        //模板并不是萬能的,有些特定數據類型,需要用具體化方式做特殊實現
        
        class Person
        {
        public:
          Person(string name, int age)
          {
            this->m_Name = name;
            this->m_Age = age;
          }
          //姓名
          string m_Name;
          //年齡
          string m_Age;
        };
        
        //對比兩個數據是否相等函數
        template<typename T>
        bool myCompare(T& a, T& b)
        {
          if (a == b)
          {
            return true;
          }
          else
          {
            return false;
          }
        }
        
        //利用具體化Person的版本來實現代碼,具體化優先調用
        template<> bool myCompare(Person& p1, Person& p2)
        {
          if (p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age)
          {
            return true;
          }
          else
          {
            return false;
          }
        }
        
        //測試
        void test01()
        {
          int a = 10;
          int b = 20;
        
          bool ret = myCompare(a, b);
        
          if (ret)
          {
            cout << "a == b" << endl;
          }
          else
          {
            cout << "a != b" << endl;
          }
        }
        
        //自定義類型對比
        void test02()
        {
          Person p1("Tom", 10);
          Person p2("Tom", 10);
        
          bool ret = myCompare(p1, p2);
        
          if (ret)
          {
            cout << "p1 == p2" << endl;
          }
          else
          {
            cout << "p1 != p2" << endl;
          }
        }
        
        int main()
        {
          //測試
          test01();
        
          test02();
        
          system("pause");
          return 0;
        }
        
      • 總結

        • 利用具體化的模板,可以解決自定義類型的通用化
        • 學習模板并不是為了寫模板,而是在STL能夠運用系統提供的模板

      類模板

      • 作用:
        • 建立一個通用類,類中的成員數據類型可以不具體制訂,用一個虛擬的類型來代表
      類模板語法
      • 語法:

        template<typename T>
        類
        
      • 解釋:

        • template --- 聲明創建模板
        • typename --- 表明其后面的符號是一種數據類型,可以用class代替
        • T --- 通用的數據類型,名稱可以替換,通常為大寫字母
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        
        //類模板
        template<class NameType,class AgeType>
        class Person
        {
        public:
          Person(NameType name, AgeType age)
          {
            this->m_Name = name;
            this->m_Age = age;
          }
        
          void showPerson()
          {
            cout << "name: " << this->m_Name << "	age: " << this->m_Age << endl;
          }
        
          string m_Name;
          int m_Age;
        };
        
        //測試
        void test01()
        {
          Person<string, int> p1("孫悟空", 999);
          p1.showPerson();
        }
        
        int main()
        {
          //測試
          test01();
        
          system("pause");
          return 0;
        }
        
      • 總結:類模板和函數模板語法相似,在聲明模板template后面加類,此類稱為類模板

      類模板與函數模板區別
      • 類模板與函數模板區別主要有兩點

        • 類模板沒有自動類型推導的使用方式
        • 類模板在模板參數列表中可以有默認參數
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        
        //類模板與函數模板的區別
        template<class NameType,class AgeType = int> //<默認參數列表>
        class Person
        {
        public:
          Person(NameType name, AgeType age)
          {
            this->m_Name = name;
            this->m_Age = age;
          }
        
          void showPerson()
          {
            cout << "name: " << this->m_Name << "	age: " << this->m_Age << endl;
          }
        
          string m_Name;
          int m_Age;
        };
        
        //1、類模板沒有自動類型推導使用方法
        void test01()
        {
          //Person p1("孫悟空", 999);錯誤  無法用自動類型推導
        
          Person<string, int> p1("孫悟空", 999);  //正確   只能用顯式指定類型
          p1.showPerson();
        }
        
        //2、類模板在模板參數列表中可以有默認參數
        void test02()
        {
          Person<string> p2("豬八戒", 1000); //類模板中的模板參數列表  可以指定默認參數
          p2.showPerson();
        }
        
        int main()
        {
          //測試
          test01();
          test02();
        
          system("pause");
          return 0;
        }
        
      • 總結:

        • 類模板使用只能用顯示指定類型方式
        • 模板中的模板參數列表可以有默認參數
      類模板中成員函數創建時機
      • 類模板中成員函數和普通類中成員函數創建時機是有區別的:

        • 普通類中的成員函數一開始就可以創建
        • 類模板中的成員函數在調用時才創建
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        
        //類模板中成員函數創建時機
        //類模板中成員函數在調用時采取創建
        
        class Person1
        {
        public:
          void showPerson1()
          {
            cout << "Person1 show" << endl;
          }
        };
        
        class Person2
        {
        public:
          void showPerson2()
          {
            cout << "Person2 show" << endl;
          }
        };
        
        template<class T>
        class MyClass
        {
        public:
          T obj;
        
          //類模板中的成員函數并不是一開始就創建的,而是在模板調用時再生成
          void func1()
          {
            obj.showPerson1();
          }
        
          void func2()
          {
            obj.showPerson2();
          }
        };
        
        void test01()
        {
          MyClass<Person1>m;
          m.func1();
          //m.func2();   //編譯會出錯,說明函數調用才會去創建成員函數
        }
        
        int main()
        {
          //測試
          test01();
          
          system("pause");
          return 0;
        }
        
      類模板對象做函數參數
      • 類模板實例化出的對象,向函數傳參的方式

      • 一共有三種傳入方式:

        • 指定傳入的類型 --- 直接顯示對象的數據類型
        • 參數模板化 --- 將對象中的參數變為模板進行傳遞
        • 整個類模板化 --- 將這個對象類型模板化進行傳遞
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        
        //類模板的對象做函數參數
        template<class T1,class T2>
        class Person
        {
        public:
            Person(T1 name, T2 age)
            {
                this->m_Name = name;
                this->m_Age = age;
            }
        
            void showPerson()
            {
                cout << "姓名:" << this->m_Name << " 年齡:" << this->m_Age << endl;
            }
        
            T1 m_Name;
            T2 m_Age;
        
        };
        
        //1、指定傳入類型
        void printPerson01(Person<string, int>&p)
        {
            p.showPerson();
        }
        
        void test01()
        {
            Person<string, int> p("孫悟空", 999); 
            printPerson01(p);
        }
        
        //2、參數模板化
        template<class T1,class T2>
        void printPerson02(Person<T1, T2>&p2)
        {
            p2.showPerson();
            cout << "T1 的類型為:" << typeid(T1).name() << endl;
            cout << "T2 的類型為:" << typeid(T2).name() << endl;
        }
        
        void test02()
        {
            Person<string, int> p2("豬八戒", 1000);
            printPerson02(p2);
        }
        
        //3、整個類模板化
        template<class T>
        void printPerson03(T &p)
        {
            p.showPerson();
            cout << "T 的類型為:" << typeid(T).name() << endl;
        }
        
        void test03()
        {
            Person<string, int> p3("唐僧", 30);
            printPerson03(p3);
        }
        

        int main()
        {
        //測試
        test01();

        test02();
        
        test03();
        
        system("pause");
        return 0;
        

        }

      • 總結:

        • 通過類模板創建的對象,可以有三種方式向函數中進行傳參
        • 使用比較廣泛是第一種:指定傳入的類型
      類模板與繼承
      • 當類模板碰到繼承時,需要注意以下幾點:
        • 當子類繼承的父類是一個類模板時,子類在聲明的時候,要指定出父類中T的類型
        • 如果不指定,編譯器無法給子類分配內存
        • 如果想靈活指定出父類中T的類型,子類也需變為類模板
      • 示例:
        #include<iostream>
        using namespace std;
        #include<string>
        
        //類模板與繼承
        template<class T>
        class Base
        {
            T m;
        };
        
        //class Son :public Base  //錯誤,必須要知道父類中的T類型,才能繼承給子類
        class Son:public Base<int>
        {
        
        };
        
        void test01()
        {
            Son s1;
        }
        
        //如果想靈活指定父類中T類型,子類也需要變類模板
        template<class T1,class T2>
        class Son2 :public Base<T2>
        {
        public:
            Son2()
            {
                cout << "T1的類型為:" << typeid(T1).name() << endl;
                cout << "T2的類型為:" << typeid(T2).name() << endl;
            }
            T1 obj;
        };
        
        void test02()
        {
            Son2<int, char>S2;
        }
        
        int main()
        {
            //測試
            test01();
            test02();
            system("pause");
            return 0;
        }
        
      類模板成員函數類外實現
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        
        //類模板與繼承
        template<class T1,class T2>
        class Person
        {
        public:
            //成員函數類內聲明
            Person(T1 name, T2 age);
            /*{
                this->m_Name = name;
                this->m_Age = age;
            }*/
        
            void showPerson()
            /*{
                cout << "姓名:" << this->m_Name << " 年齡:" << this->m_Age << endl;
            }*/
        
            T1 m_Name;
            T2 m_Age;
        };
        
        //構造函數 類外實現
        template<class T1,class T2>
        Person<T1,T2>::Person(T1 name, T2 age)
        {
            this->m_Name = name;
            this->m_Age = age;
        }
        
        //成員函數 類外實現
        template<class T1, class T2>
        void Person<T1,T2>::showPerson()
        {
            cout << "姓名:" << this->m_Name << " 年齡:" << this->m_Age << endl;
        }
        
        void test01()
        {
            Person<string, int> p("tom", 20);
            p.showPerson();
        }
        
        int main()
        {
            //測試
            test01();
          
            system("pause");
            return 0;
        }
        
      • 總結:類模板中成員函數類外實現時,需要加上模板參數列表

      類模板份文件編寫
      • 類模板成員函數分文件編寫產生的問題以及解決方式

      • 問題:

        • 類模板中成員函數創建時機是在調用階段,導致分文件編寫時鏈接不到
      • 解決:

        • 解決方式1:直接包含.cpp源文件
        • 解決方式2:將聲明和實現寫到同一個文件中,并更改后綴名為.hpp,hpp是約定的名稱,并不是強制
      • 示例:
        person.hpp代碼:

        #pragma once
        #include<iostream>
        using namespace std;
        #include<string>
        
        //類模板分文件編寫問題以及解決
        template<class T1, class T2>
        class Person
        {
        public:
        
            Person(T1 name, T2 age);
            /*{
                this->m_Name = name;
                this->m_Age = age;
            }*/
        
            void showPerson();
            /*{
                cout << "姓名:" << this->m_Name << " 年齡:" << this->m_Age << endl;
            }*/
        
            T1 m_Name;
            T2 m_Age;
        };
        
        //構造函數類外實現
        template<class T1, class T2>
        Person<T1, T2>::Person(T1 name, T2 age)
        {
            this->m_Name = name;
            this->m_Age = age;
        }
        
        //成員函數類外實現
        template<class T1, class T2>
        void Person<T1, T2>::showPerson()
        {
            cout << "姓名:" << this->m_Name << " 年齡:" << this->m_Age << endl;
        }
        

        main主函數入口.cpp

        #include<iostream>
        using namespace std;
        #include<string>
        //第一種解決方式,直接包含 源文件
        #include"person.cpp"
        
        //第二種解決方式,將.h和.cpp種的內容寫到一起,將后綴名改為.hpp文件
        #include"person.hpp"
        
        //#include<string>
        //
        ////類模板分文件編寫問題以及解決
        //template<class T1,class T2>
        //class Person
        //{
        //public:
        //
        //    Person(T1 name, T2 age);
        //    /*{
        //        this->m_Name = name;
        //        this->m_Age = age;
        //    }*/
        //
        //    void showPerson();
        //    /*{
        //        cout << "姓名:" << this->m_Name << " 年齡:" << this->m_Age << endl;
        //    }*/
        //
        //    T1 m_Name;
        //    T2 m_Age;
        //};
        
        ////構造函數類外實現
        //template<class T1,class T2>
        //Person<T1,T2>::Person(T1 name, T2 age)
        //{
        //    this->m_Name = name;
        //    this->m_Age = age;
        //}
        //
        ////成員函數類外實現
        //template<class T1, class T2>
        //void Person<T1,T2>::showPerson()
        //{
        //    cout << "姓名:" << this->m_Name << " 年齡:" << this->m_Age << endl;
        //}
        
        void test01()
        {
            Person<string, int> p("tom", 20);
            p.showPerson();
        }
        
        int main()
        {
            //測試
            test01();
          
            system("pause");
            return 0;
        }
        
      • 總結:主流的解決方式是第二種,將類模板成員函數寫到一起,并將后綴名改為.hpp

      類模板與友元
      • 類模板配合友元函數的類內和類外實現

      • 全局函數雷內實現 - 直接在類內聲明友元即可

      • 全局函數類外實現 - 需要提前讓編譯器知道全局函數的存在

      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        
        //通過全局函數配合友元  打印Person信息
        
        //提前讓編譯器知道Person類存在
        //先做函數模板聲明,下方再做函數模板定義,再做友元
        template<class T1,class T2>
        class Person;
        
        //全局函數  類外實現  可以先聲明函數模板,讓編譯器提前知道這個函數的存在
        template<typename T1, typename T2>
        void PrintPerson2(Person<T1, T2>p);
        
        template<typename T1,typename T2>
        class Person
        {
            //全局函數  類內實現
            friend void PrintPerson(Person<T1, T2>p)
            {
                cout << "姓名:" << p.m_Name << " 年齡:" << p.m_Age << endl;
            }
        
            //全局函數  類外實現
            //加空模板參數列表 【 < > 】
            //如果全局函數  是類外實現,需要讓編譯器提前知道這個函數的存在
            friend void PrintPerson2<>(Person<T1,T2>p);
        
        public:
            Person(T1 name, T2 age)
            {
                this->m_Name = name;
                this->m_Age = age;
            }
        
        private:
            T1 m_Name;
            T2 m_Age;
        };
        
        //全局函數  類外實現
        template<typename T1, typename T2>
        void PrintPerson2(Person<T1, T2>p)
        {
            cout << "類外實現---姓名:" << p.m_Name << " 年齡:" << p.m_Age << endl;
        }
        
        //1、全局函數在類內實現
        void test01()
        {
            Person<string, int>p("Tom", 20);
            PrintPerson(p);
        }
        
        //2、全局函數在類外實現
        void test02()
        {
            Person<string, int>p1("Cat", 5);
            PrintPerson2(p1);
        }
        
        int main()
        {
            //測試
            test01();
            test02();
          
            system("pause");
            return 0;
        }
        
      • 總結:建議全局函數做類內實現,用法簡單,而且編譯器可以直接識別

      類模板案例
      • 案例描述:實現一個通用的數組類,要求如下

        • 可以對內置數據類型以及自定義數據類型的數據進行存儲
        • 將數組中的數據存儲到堆區
        • 構造函數中可以傳入數組的容量
        • 提供對應的拷貝構造函數以及operator=防止淺拷貝問題
        • 提供尾插法和尾刪法對數組中的數據進行增加和刪除
        • 可以通過下標的方式訪問數組中的元素
        • 可以獲取數組中當前元素個數和數組的容量
      • 示例:
        MyArray.hpp

        //自己通用的數組類
        #pragma once
        #include<iostream>
        using namespace std;
        
        template<class T>
        class MyArray
        {
        public:
          //有參構造  參數 容量
          MyArray(int capacity)
          {
            cout << "MyArray 有參構造調用" << endl;
            this->m_Capacity = capacity;
            this->m_Size = 0;
            this->pAddress = new T[capacity];
          }
        
          //拷貝構造
          MyArray(const MyArray& arr)
          {
            cout << "MyArray 拷貝構造調用" << endl;
            this->m_Capacity = arr.m_Capacity;
            this->m_Size = arr.m_Size;
        
            //淺拷貝的問題會導致堆區數據重復釋放
            //this->pAddress = arr.pAddress;
        
            //深拷貝
            this->pAddress = new T[arr.m_Capacity];
        
            //將arr中的數據都拷貝過來
            for (int i = 0; i < this->m_Size; i++)
            {
              //如果T為對象,而且還包含指針,必須重載【=】操作符,因為這個等號不是構造而是賦值
              //普通類型可以直接【=】,但是指針類型需要深拷貝
              this->pAddress[i] = arr.pAddress[i];
            }
          }
        
          //operator= 防止淺拷貝問題
          MyArray& operator=(const MyArray &arr)
          {
            cout << "MyArray 的operator=調用" << endl;
            //先判斷原來堆區是否有數據,如果有先釋放
            if (this->pAddress != NULL)
            {
              delete[]this->pAddress;
              this->pAddress = NULL;
              this->m_Capacity = 0;
              this->m_Size = 0;
            }
        
            //深拷貝
            this->m_Capacity = arr.m_Capacity;
            this->m_Size = arr.m_Size;
            this->pAddress = new T[arr.m_Capacity];
            for (int i = 0; i < this->m_Size; i++)
            {
              this->pAddress[i] = arr.pAddress[i];
            }
            return *this;
          }
          
          //尾插法
          void Push_Back(const T& val)
          {
            //先判斷容量時候等于大小
            if (this->m_Capacity == this->m_Size)
            {
              return;
            }
            this->pAddress[this->m_Size] = val;  //再數組末尾插入數據
            this->m_Size++;//更新數組長度
          }
        
          //尾刪法
          void Pop_Back()
          {
            //讓用戶訪問不到最后一個元素,即為尾刪,邏輯刪除
            if (this->m_Size == 0) //判斷數組長度是否為0,如果為0,代表數組無數據
            {
              return;
            }
        
            this->m_Size--; //更新數組長度
        
          }
        
          //通過下標方式訪問數組中的元素  函數調用返回一個左值,需要返回一個引用【&】
          //重載【 [] 】操作符 arr[0]
          T& operator[](int index)
          {
            return this->pAddress[index];//不考慮越界,用戶自己去處理
          }
        
          // 返回數組容量
          int getCapacity()
          {
            return this->m_Capacity;
          }
        
          //返回數組長度
          int getSize()
          {
            return this->m_Size;
          }
        
          //析構函數
          ~MyArray()
          {
            cout << "MyArray 析構調用" << endl;
            if (this->pAddress != NULL)
            {
              delete[]this->pAddress;
              this->pAddress = NULL;
            }
          }
        
        private:
          T* pAddress;//指針指向堆區開辟的真實數組
          int m_Capacity;//數組容量
          int m_Size;//數組長度
        };
        

        主函數.cpp

        #include<iostream>
        using namespace std;
        #include<string>
        #include"MyArray.hpp"
        
        //打印函數  引用傳遞方式
        void printInArray(MyArray<int>& arr)
        {
            //i < MyArray里面的getm_Size的int類型返回值
            for (int i = 0; i < arr.getSize(); i++)
            {
                cout << arr[i] << endl;
            }
        }
        

        //1、全局函數在類內實現
        void test01()
        {
        //創建一個MyArry類型數組 傳入變量類型為int 數組容量為5
        MyArray arr1(5);
        for (int i = 0; i < 5; i++)
        {
        //利用尾插法向數組中插入數據
        //傳入i的值
        arr1.Push_Back(i);
        }
        cout << "arr1的打印輸出:" << endl;
        //向打印函數中傳數組
        printInArray(arr1);
        //查看數組容量與長度
        cout << "arr1的容量為:" << arr1.getCapacity() << endl;
        cout << "arr1的長度為:" << arr1.getSize() << endl;

        //創建一個MyArry類型數組 傳入變量類型為int arr2數組值等于arr1數組的值  深拷貝 new一個新空間
        MyArray<int>arr2(arr1);
        
        //尾刪
        arr2.Pop_Back();
        printInArray(arr2);
        cout << "arr2尾刪后:" << endl;
        cout << "arr2的容量為:" << arr2.getCapacity() << endl;
        cout << "arr2的長度為:" << arr2.getSize() << endl;
        
        //創建一個MyArry類型數組 傳入變量類型為int  數組容量為100
        MyArray<int>arr3(100);
        ////創建一個MyArry類型數組 傳入變量類型為int arr3數組值等于arr1數組的值  深拷貝 new一個新空間 operator= 防止淺拷貝問題
        arr3 = arr1;
        

        }

        //測試自定義數據類型
        class Person
        {
        public:

        Person() {};
        Person(string name, int age)
        {
            this->m_Name = name;
            this->m_Age = age;
        }
        
        string m_Name;
        int m_Age;
        

        };

        //打印數組
        void printPersonArray(MyArray&arr)
        {
        for (int i = 0; i < arr.getSize(); i++)
        {
        cout << "姓名:" << arr[i].m_Name << " 年齡:" << arr[i].m_Age << endl;
        }
        }

        void test02()
        {
        MyArrayarr(10);
        Person p1("孫悟空", 999);
        Person p2("韓信", 30);
        Person p3("妲己", 20);
        Person p4("趙云", 25);
        Person p5("安其拉", 27);

        //將數據插入到數組中
        arr.Push_Back(p1);
        arr.Push_Back(p2);
        arr.Push_Back(p3);
        arr.Push_Back(p4);
        arr.Push_Back(p5);
        //打印函數調用
        printPersonArray(arr);
        //輸出容量
        cout << "arr容量為:" << arr.getCapacity() << endl;
        //輸出長度
        cout << "arr長度為:" << arr.getSize() << endl;
        

        }

        int main()
        {
        //測試
        test01();
        test02();

        system("pause");
        return 0;
        

        }

        打印結果:
        ```cpp
        0
        1
        2
        3
        4
        arr1的容量為:5
        arr1的長度為:5
        MyArray 拷貝構造調用
        0
        1
        2
        3
        arr2尾刪后:
        arr2的容量為:5
        arr2的長度為:4
        MyArray 有參構造調用
        MyArray 的operator=調用
        MyArray 析構調用
        MyArray 析構調用
        MyArray 析構調用
        MyArray 有參構造調用
        姓名:孫悟空 年齡:999
        姓名:韓信 年齡:30
        姓名:妲己 年齡:20
        姓名:趙云 年齡:25
        姓名:安其拉 年齡:27
        arr容量為:10
        arr長度為:5
        MyArray 析構調用
        
      • 總結:能夠利用所學知識點實現通用的數組

      STL初識

      STL的誕生

      • 軟件界一直希望建立一種可重復利用的東西
      • C++的面向對象和泛型編程思想,目的就是復用性的提升
      • 數據結構和算法都未能有一套標準,導致被迫從事大量重復工作
      • 建立數據結構和算法的一套標準,誕生了STL

      STL基本概念

      • STL(Standard Template Library,標準模板庫)
      • STL從廣義上分為:容器(container)算法(algorithm)迭代器(iterator)
      • 容器和算法之間通過迭代器進行無縫連接
      • STL幾乎所有的代碼都采用了模板類或者模板函數

      STL六大組件

      • STL答題分為六大組件,分別是:容器、算法、迭代器、仿函數、適配器(配接器)、空間配置器
        • 容器:各種數據結構,如vector、list、deque、set、map等,用來存放數據
        • 算法:各種常用的算法,如sort、find、copy、for_each等
        • 迭代器:扮演了容器與算法之間的膠合劑
        • 仿函數:行為類似函數,可作為算法的某種策略
        • 適配器:一種用來修飾容器或者仿函數或迭代器接口的東西
        • 空間配置器:負責空間的配置與管理

      STL中容器、算法、迭代器

      • 容器:置物之所也
      • STL容器就是將運用最廣泛的一些數據結構實現出來
      • 常用的數據結構:數組、鏈表、樹、棧、隊列、集合、映射表等
      • 這些容器分為序列式容器和關聯式容器兩種
        • 序列式容器:強調值的排序,序列式容器中的每個元素均有固定的位置
        • 關聯式容器:二叉樹結構,各元素之間沒有嚴格的物理上的順序關系
      • 算法:問題之解法也
      • 有限的步驟,解決邏輯或數學上的問題,這一門學科我們叫做算法(Algorithms)
      • 算法分為質變算法和非質變算法
        • 質變算法:是指運算過程中會更改區間內的元素的內容。例如拷貝、替換、刪除等
        • 非質變算法:是指運算過程中不會更改區間內的元素內容,例如查找、計數、遍歷、尋找極值等等
      • 迭代器:容器和算法之間粘合劑
      • 提供一種方法,使之能夠依序尋訪某個容器所含的各個元素,而又無需暴露該容器的內部表示方式
      • 每個容器都有自己專屬的迭代器
      • 迭代器使用非常類似于指針,初學階段我們可以先理解迭代器為指針
      • 迭代器種類
      種類 功能 支持運算
      輸入迭代器 對數據的只讀訪問 只讀,支持++、==、!=
      輸出迭代器 對數據的只寫訪問 只寫、支持++
      前向迭代器 讀寫操作,并能向前推進迭代器 讀寫、支持++、==、!=
      雙向迭代器 讀寫操作,并能向前和向后操作 讀寫,支持++、--
      隨機訪問迭代器 讀寫操作,可以以跳躍的方式訪問任意數據,功能最強的迭代器 讀寫,支持++、--、[n]、-n、<、<=、>、>=
      • 常用的容器種迭代器種類為雙向迭代器,和隨機訪問迭代器

      容器算法迭代器初識

      • STL中最常用的容器為vector,可以理解為數組,下面我們將學習如果向這個容器中插入數據,并遍歷這個容器
      vector存放內置數據類型
      • 容器:vector

      • 算法:for_each

      • 迭代器:vector::iterator

      • 示例:

        #include<iostream>
        using namespace std;
        #include<vector>
        #include<algorithm>  //標準算法頭文件
        
        //vector容器存放內置數據類型
        void myPrint(int val)
        {
          cout << val << endl;
        }
        
        void test01()
        {
          //創建一個vector容器,數組   需要包含#include<vector>  vector的頭文件
          vector<int> v;
        
          //向容器中插入數據
          v.push_back(10);
          v.push_back(20);
          v.push_back(30);
          v.push_back(40);
          v.push_back(50);
        
          
          //通過迭代器訪問容器中的數據
          //vector<int>::iterator 拿到vector<int>這種容器的迭代器類型
          vector<int>::iterator itBegin = v.begin();  //起始迭代器 指向容器中第一個元素
          vector<int>::iterator itEnd = v.end();  //結束迭代器,指向容器中最后一個元素的下一個位置
        
          //第一種遍歷方式
          while (itBegin != itEnd)
          {
            cout << *itBegin << endl;
            itBegin++;
          }
          cout << endl;
        
          //第二種遍歷方式
          for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
          {
            cout << *it << endl;
          }
          cout << endl;
        
          //第三章遍歷方式  利用STL提供遍歷算法
          for_each(v.begin(), v.end(), myPrint);
        
        }
        
        int main()
        {
          //測試
          test01();
        
          system("pause");
          return 0;
        }
        

        運行結果

        10
        20
        30
        40
        50
        
        10
        20
        30
        40
        50
        
        10
        20
        30
        40
        50
        
      vector存放自定義數據類型
      • 學習目標:vector中存放自定義數據類型,并打印輸出

      • 示例

        #include<iostream>
        using namespace std;
        #include<vector>
        #include<algorithm>  //標準算法頭文件
        #include<string>
        
        //vector容器存放自定義數據類型
        class Person
        {
        public:
          Person(string name, int age)
          {
            this->m_Name = name;
            this->m_Age = age;
          }
        
          string m_Name;
          int m_Age;
        };
        
        void test01()
        {
          vector<Person> v;
        
          Person p1("aaa", 10);
          Person p2("bbb", 15);
          Person p3("ccc", 20);
          Person p4("ddd", 25);
          Person p5("eee", 30);
        
          //向容器中添加數據
          v.push_back(p1);
          v.push_back(p2);
          v.push_back(p3);
          v.push_back(p4);
          v.push_back(p5);
        
          //遍歷容器中的數據
          cout << "自定義類型存數據" << endl;
          for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
          {
            cout << "*解引用  姓名:" << (*it).m_Name << " 年齡:" << (*it).m_Age << endl;
            cout << "this指針 姓名:" << it->m_Name << " 年齡:" << it->m_Age << endl;
            cout << endl;
          }
        }
        
        //存放指定值數據類型  指針
        void test02()
        {
          vector<Person*> v;
        
          Person p1("aaa", 10);
          Person p2("bbb", 15);
          Person p3("ccc", 20);
          Person p4("ddd", 25);
          Person p5("eee", 30);
        
          //向容器中添加數據  傳址
          v.push_back(&p1);
          v.push_back(&p2);
          v.push_back(&p3);
          v.push_back(&p4);
          v.push_back(&p5);
        
          //遍歷容器
          cout << endl;
          cout << "自定義類型存地址" << endl;
          for (vector<Person*>::iterator it = v.begin(); it != v.end(); it++)
          {
            cout << "this指針 姓名:" << (*it)->m_Name << " 年齡:" << (*it)->m_Age << endl;
            cout << "*解引用  姓名:" << (*(*it)).m_Name << " 年齡:" << (*(*it)).m_Age << endl;
            cout << endl;
          }
        }
        
        int main()
        {
          //測試
          test01();
          test02();
        
          system("pause");
          return 0;
        }
        

        運行結果

        *解引用  姓名:bbb 年齡:15
        this指針 姓名:bbb 年齡:15
        
        *解引用  姓名:ccc 年齡:20
        this指針 姓名:ccc 年齡:20
        
        *解引用  姓名:ddd 年齡:25
        this指針 姓名:ddd 年齡:25
        
        *解引用  姓名:eee 年齡:30
        this指針 姓名:eee 年齡:30
        

        自定義類型存地址
        this指針 姓名:aaa 年齡:10
        *解引用 姓名:aaa 年齡:10

        this指針 姓名:bbb 年齡:15
        *解引用 姓名:bbb 年齡:15

        this指針 姓名:ccc 年齡:20
        *解引用 姓名:ccc 年齡:20

        this指針 姓名:ddd 年齡:25
        *解引用 姓名:ddd 年齡:25

        this指針 姓名:eee 年齡:30
        *解引用 姓名:eee 年齡:30

      vector容器嵌套容器
      • 容器中嵌套容器,將所有數據進行遍歷輸出

      • 示例:

        #include<iostream>
        using namespace std;
        #include<vector>
        #include<algorithm>  //標準算法頭文件
        #include<string>
        
        //vector容器嵌套容器
         void test01()
        {
          vector<vector<int>> v;
        
          //創建小容器
          vector<int> v1;
          vector<int> v2;
          vector<int> v3;
          vector<int> v4;
        
          //向小容器中添加數據
          for (int i = 0; i < 4; i++)
          {
            v1.push_back(i + 1);
            v2.push_back(i + 2);
            v3.push_back(i + 3);
            v4.push_back(i + 4);
          }
        
          //將小容器插入到大容器中
          v.push_back(v1);
          v.push_back(v2);
          v.push_back(v3);
          v.push_back(v4);
        
          //通過大容器,把所有數據遍歷
          for (vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++)
          {
            //  (*it) --- 指的是容器vector<int>
            for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
            {
              cout << *vit << " ";
            }
            cout << endl;
          }
        
        }
        
        int main()
        {
          //測試
          test01();
        
          system("pause");
          return 0;
        }
        

        運行結果:

        1 2 3 4
        2 3 4 5
        3 4 5 6
        4 5 6 7
        

      STL-常用容器

      string容器

      string基本概念
      • 本質:
        • string是C++風格的字符串,而string本質上是一個類
      • string和char * 區別:
        • char *是一個指針
        • string是一個類,類內部封裝了char,管理這個字符串,是一個char型容器
      • 特點:
        • string類內部封裝了很多成員方法
        • 例如:查找find、拷貝copy、刪除delete、替換replace、插入insert
        • string管理char*所分配的內存,不用擔心復制越界和取值越界等,由類內部進行負責
      string構造函數
      • string(); //創建一個空的字符串 例如:string str;

      • string(const char * s); //使用字符串s初始化

      • string(const string & str); //使用一個string對象初始化另一個string對象

      • string(int n,char c); //使用n個字符c初始化

      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        
        //string構造函數
        void test01()
        {
          //默認構造
          string s1;
        
          //初始化
          const char* str = "hello world";
          string s2(str);
        
          cout << "s2 = " << s2 << endl;
        
          //拷貝構造
          string s3(s2);
          cout << "s3 = " << s3 << endl;
        
          ////使用n個字符初始化
          string s4(10, 'a');
          cout << "s4 = " << s4 << endl;
        }
        
        int main()
        {
          //測試
          test01();
        
          system("pause");
          return 0;
        }
        

        運行結果:

        s2 = hello world
        s3 = hello world
        s4 = aaaaaaaaaa
        
      • 總結:string的多種構造方式沒有可比性,靈活使用即可

      string賦值操作
      • 功能描述:給string字符串進行賦值

      • 賦值的函數原型

        • string& openator=(const char* s); //char*類型字符串 賦值給當前的字符串
        • string& openator=(const string &s) //把字符串s賦值給當前的字符串
        • string& openator=(char c); //字符賦值給當前的字符串
        • string& assign(const char *s); //把字符串s賦給當前的字符串
        • string& assign(const char *s,int n);//把字符串s的前n個字符賦給當前的字符串
        • string& assign(const string &s); //把字符串s賦給當前字符串
        • string& assign(int n,char c); //把n個字符c賦給當前字符串
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        
        //string賦值操作
        void test01()
        {
          //第一種方法
          string str1;
          str1 = "hello world";
          cout << "第一種方法  str1 = " << str1 << endl;
        
          //第二種方法
          string str2;
          str2 = str1;
          cout << "第二種方法  str2 = " << str2 << endl;
        
          //第三種方法
          string str3;
          str3 = 'a';
          cout << "第三種方法  str3 = " << str3 << endl;
        
          //第四種方法
          string str4;
          str4.assign("hello C++");
          cout << "第四種方法  str4 = " << str4 << endl;
        
          //第五種方法
          string str5;
          str5.assign("hello C++", 5);
          cout << "第五種方法  str5 = " << str5 << endl;
        
          //第六種方法
          string str6;
          str6.assign(str5);
          cout << "第六種方法  str6 = " << str6 << endl;
        
          //第七種方法
          string str7;
          str7.assign(10, 'w');
          cout << "第七種方法  str7 = " << str7 << endl;
        
        }
        
        int main()
        {
          //測試
          test01();
        
          system("pause");
          return 0;
        }
        

        運行結果:

        第一種方法  str1 = hello world
        第二種方法  str2 = hello world
        第三種方法  str3 = a
        第四種方法  str4 = hello C++
        第五種方法  str5 = hello
        第六種方法  str6 = hello
        第七種方法  str7 = wwwwwwwwww
        
      • 總結:string的賦值方式很多,一般 operator= 的方式比較實用

      字符串拼接
      • 實現在字符串末尾憑借字符串

      • 函數原型

        • string& operator+=(const char* str); //重載+=操作符
        • string& operator+=(const char str); //重載+=操作符
        • string& operator+=(const string* str); //重載+=操作符
        • string& append(const char* s); //把字符串s連接到當前字符串結尾
        • string& append(const char* s,int n); //把字符串s的前n個字符連接到當前字符串結尾
        • string& append(const string& s); //同operator+=(const String& str);
        • string& append(const string& s,int pos,int n);//把字符串s中從pos開始的n個字符連接到字符串結尾
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        
        //string字符串拼接
        void test01()
        {
          string str1 = "我";
        
          //第一種用法
          str1 += "愛玩游戲";
          cout << "第一種方法 str1 = " << str1 << endl;
        
          //第二種方法
          str1 += ":";
          cout << "第二種方法 str1 = " << str1 << endl;
        
          //第三種方法
          string str2 = "LOL DNF";
          str1 += str2;
          cout << "第三種方法 str1 = " << str1 << endl;
        
          //第四種方法
          string str3 = "I";
          str3.append(" Love ");
          cout << "第四種方法 str1 = " << str3 << endl;
        
          //第五種方法
          str3.append("game: abcde", 5);
          cout << "第五種方法 str1 = " << str3 << endl;
        
          //第六種方法
          str3.append(str2);
          cout << "第六種方法 str1 = " << str3 << endl;
        
          //第七種方法
          string str4 = " CF DATA2";
          str3.append(str4, 0, 4);     //只截取string字符串的元素下標0-4的字符
          cout << "第七種方法 str1 = " << str3 << endl;
        
        }
        
        int main()
        {
          //測試
          test01();
        
          system("pause");
          return 0;
        }
        

        運行結果:

        第一種方法 str1 = 我愛玩游戲
        第二種方法 str1 = 我愛玩游戲:
        第三種方法 str1 = 我愛玩游戲:LOL DNF
        第四種方法 str1 = I Love
        第五種方法 str1 = I Love game:
        第六種方法 str1 = I Love game:LOL DNF
        第七種方法 str1 = I Love game:LOL DNF CF
        
      string查找和替換
      • 功能描述

        • 查找:查找指定字符串是否存在
        • 替換:在指定的位置替換字符串
      • 函數原型:

        • int find(const string& str,int pos = 0) const; //查找str第一次出現位置,從pos開始查找
        • int find(const char* s,int pos = 0) const; //查找s第一次出現位置,從pos開始查找
        • int find(const char* s,int pos,int n) const; //從pos位置查找s的前n個字符第一次位置
        • int find(const char c,int pos = 0) const; //查找字符c第一次出現位置
        • int rfind(const string& str,int pos = npos) const;//查找str最后一次位置,從pos開始查找
        • int rfind(const char* s,int pos = npos) const; //查找s最后一次出現位置,從pos開始查找
        • int rfind(const char* s,int pos,int n) const; //從pos查找s的前n個字符最后一次位置
        • int rfind(const char s,int pos = 0) const; //查找字符c最后一次出現位置
        • string& replace(int pos,int a,const string& str); //替換從pos開始n個字符為字符串str
        • string& replace(int pos,int a,const char* s); //替換從pos開始的n個字符為字符串s
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        
        //string字符串查找和替換
        
        //1、查找
        void test01()
        {
          string str1 = "abcdefgde";
          //第一種方法  從頭開始查找字符c在當前字符串的位置
          int pos = str1.find("de");
        
          //通常要判斷一下
          if (pos == -1)  //未找到返回值為-1  pos值如果為-1  代表未找到
          {
            cout << "未找到字符串" << endl;
          }
          else
          {
            cout << "第一種方法  pos = " << pos << endl;  //返回第一次出現的下標位置
          }
        
          //第一種方法find與第五種方法rfind
          //區別:rfind從右往左查找  find從左往右查找
          pos = str1.rfind("de");
          if (pos == -1)
          {
            cout << "未找到字符串" << endl;
          }
          else
          {
            cout << "第五種方法  pos = " << pos << endl;
          }
          //第二種方法  從pos開始查找字符串s在當前串中的位置
          pos = str1.find("f", 0);
          if (pos == -1)
          {
            cout << "未找到字符串" << endl;
          }
          else
          {
            cout << "第二種方法  pos = " << pos << endl;
          }
          
          //第二種方法  從pos開始查找字符串s在當前串中的位置
          pos = str1.find("f", 2);
          if (pos == -1)
          {
            cout << "未找到字符串" << endl;
          }
          else
          {
            cout << "第二種方法  pos = " << pos << endl;
          }
        
          //第三種方法
          //從str1元素下標0的位置開始查找字符串"fgsk"前2位字符在當前串中的位置
          pos = str1.find("fgsk", 0, 2);
          if (pos == -1)
          {
            cout << "未找到字符串" << endl;
          }
          else
          {
            cout << "第三種方法  pos = " << pos << endl;
          }
        
          //第四種方法  從pos開始查找字符c在當前串中第一次出現的位置
          pos = str1.find('d');
          if (pos == -1)
          {
            cout << "未找到字符串" << endl;
          }
          else
          {
            cout << "第四種方法  pos = " << pos << endl;
          }
        
          //第六種方法   元素下標【5】開始從右往左查找最后一次的位置
          pos = str1.rfind("d", 5);
          if (pos == -1)
          {
            cout << "未找到字符串" << endl;
          }
          else
          {
            cout << "第六種方法  pos = " << pos << endl;
          }
        
          //第六種方法  第二次查找   從右往左查找第一個字符【d】
          pos = str1.rfind("d");
          if (pos == -1)
          {
            cout << "未找到字符串" << endl;
          }
          else
          {
            cout << "第六種方法  pos = " << pos << endl;
          }
        
          //第七種方法   查找字符串的前兩個字符  從最后一次位置開始  str1.size()表示最后一次位置
          pos = str1.rfind("defg", str1.size(), 2);
          if (pos == -1)
          {
            cout << "未找到字符串" << endl;
          }
          else
          {
            cout << "第七種方法  pos = " << pos << endl;
          }
        
          //第八種方法  從右往左查找字符第一次出現的位置 str1.size()表示最后一個元素下標位置
          pos = str1.rfind('d',str1.size());
          if (pos == -1)
          {
            cout << "未找到字符串" << endl;
          }
          else
          {
            cout << "第八種方法  pos = " << pos << endl;
          }
        }
        
        //2、替換
        void test02()
        {
          //第九種方法  替換 
          string str1 = "abcdefgde";
          //從元素下標【1】開始,往后3個字符替換為“1234”
          str1.replace(1, 3, "1234");
          if (str1.size()>1)
          {
            cout << "第九種方法  替換  str1 = " << str1 << endl;
          }
          else
          {
            cout << "字符串元素下標小于1,無法完成替換" << endl;
          }
        
          //第十種方法  替換
          str1.replace(2, 4, "567890");
          if (str1.size() > 1)
          {
            cout << "第九種方法  替換  str1 = " << str1 << endl;
          }
          else
          {
            cout << "字符串元素下標小于1,無法完成替換" << endl;
          }
        
        }
        
        int main()
        {
          //測試
          test01();
          test02();
        
          system("pause");
          return 0;
        }
        

        運行結果

        第一種方法  pos = 3
        第五種方法  pos = 7
        第二種方法  pos = 5
        第二種方法  pos = 5
        第三種方法  pos = 5
        第四種方法  pos = 3
        第六種方法  pos = 3
        第六種方法  pos = 7
        第七種方法  pos = 7
        第八種方法  pos = 7
        第九種方法  替換  str1 = a1234efgde
        第九種方法  替換  str1 = a1567890fgde
        
      • 總結:

        • find查找是從左往右,rfind是從右往左
        • find找到字符串后返回查找的第一個字符位置,找不到返回-1
        • replace在替換時,要指定從哪個位置起,多少個字符,替換成什么樣的字符串
      string字符串比較
      • 字符串之間的比較

      • 比較方式:

        • 字符串比較是按照字符的ASCII碼進行對比
        • = 返回 0
        • > 返回 1
        • < 返回 -1
      • 函數原型:

        • int compare(const string &s) const; //與字符串s比較
        • int compare(const char *s) const; //與字符串s比較
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        
        //string字符串比較
        
        void test01()
        {
          string str1 = "hello";
          string str2 = "xello";
        
          if (str1.compare(str2) == 0)
          {
            cout << "str1 = str2" << endl;
          }
          else if (str1.compare(str2) > 0)
          {
            cout << "strl > str2" << endl;
          }
          else
          {
            cout << "str1 < str2" << endl;
          }
        
        }
        
        int main()
        {
          //測試
          test01();
          
          system("pause");
          return 0;
        }
        

        運行結果:

        str1 < str2
        
      • 總結:字符串對比主要是用于比較兩個字符串是否相等,判斷誰大誰小的意義并不是很大

      string字符存取
      • string中單個字符存取方式有兩種

        • char& operator[](int n); //通過[]方式獲取字符
        • char& at(int n); //通過at方法獲取字符
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        
        //string字符存取
        
        void test01()
        {
          string str = "hello";
        
          cout << "str = " << str << endl << endl;
        
          //1、通過 [] 訪問單個字符
          for (int i = 0; i < str.size(); i++)
          {
            cout << str[i] << " ";
          }
          cout << endl << endl;
        
          //2、通過at方式訪問單個字符
          for (int i = 0; i < str.size(); i++)
          {
            cout << str.at(i) << " ";
          }
          cout << endl << endl;
        
          //修改單個字符
          str[0] = 'x';
          cout << "str = " << str << endl << endl;
        
          str.at(1) = 'x';
          cout << "str = " << str << endl << endl;
        }
        
        int main()
        {
          //測試
          test01();
          
          system("pause");
          return 0;
        }
        

        運行結果:

        str = hello
        
        h e l l o
        
        h e l l o
        
        str = xello
        
        str = xxllo
        
      • 總結:string字符串中單個字符存取有兩種方式,利用[]或者at

      string插入和刪除
      • 作用:對string字符串進行插入和刪除字符操作

      • 函數原型:

        • string& insert(int pos,const char* s); //插入字符串
        • string& insert(int pos,const string* str); //插入字符串
        • string& insert(int pos,int n, char c); //在指定位置插入n個字符c
        • string& erase(int pos,int n = npos); //刪除從pos開始的n個字符
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        
        //string字符串插入和刪除
        
        void test01()
        {
          string str = "hello";
        
          //插入
          str.insert(1, "222");
          cout << str << endl;
        
          str.insert(4, 3, '6');
          cout << str << endl;
        
          //刪除
          str.erase(1, 6);
          cout << str << endl;
        }
        
        int main()
        {
          //測試
          test01();
          
          system("pause");
          return 0;
        }
        

        運行結果:

        h222ello
        h222666ello
        hello
        
      • 總結:插入和刪除的起始下標都是從0開始

      string子串
      • 作用:從字符串中獲取想要的子串

      • 函數原型:

        • string substr(int pos = 0;int n = npos) const; //返回由pos開始的n個字符組成的字符串
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        
        //string字符串子串
        
        void test01()
        {
          string str = "abcdef";
        
          string subStr = str.substr(1, 3);
        
          cout << "subStr = " << subStr << endl;
        }
        
        //實用操作
        void test02()
        {
          string email = "zhangsan@sina.com";
        
          //從郵件地址中  獲取 用戶名信息
          //email_name = email從0開始截取到email.rfind('@')-1的字符串   email.rfind('@')是指從右往左查找 @ 字符并返回下標
          string email_name = email.substr(0, email.rfind('@'));
        
          cout << "email_name = " << email_name << endl;
        }
        int main()
        {
          //測試
          test01();
          test02();
          
          system("pause");
          return 0;
        }
        

        運行結果:

        subStr = bcd
        email_name = zhangsan
        

      vector容器

      vector基本概念
      • 作用:vector數據結構和數組非常相似,也成為單端數組
      • vector與普通數組區別:
        • 不同之處在于數組是靜態空間,而vector可以動態擴展
      • 動態擴展:
        • 并不是在原空間之后續接新空間,而是找更大的內存空間,然后將原數據拷貝新空間,釋放原空間
      • vector容器的迭代器是支持隨機訪問的迭代器
      vector構造函數
      • 作用:創建vector容器

      • 函數原型:

        • vector v; //采用模板實現類實現,默認構造函數
        • vector(v.begin(),v.end()); //將v[begin(),end()]區間中的元素拷貝給本身
        • vector(n,elem); //溝站函數將n個elem拷貝給本身
        • vector(const vector &vec); //拷貝構造函數
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        #include<vector>
        
        //vector容器構造
        
        //打印函數
        void printVevtor(vector<int> &v)
        {
          for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
          {
            cout << *it << " ";
          }
          cout << endl;
        }
        
        void test01()
        {
          vector<int> v1;//默認構造  無參構造
        
          for (int i = 0; i < 10; i++)
          {
            v1.push_back(i);
          }
        
          printVevtor(v1);
        
          //通過區間方式進行構造
          vector<int>v2(v1.begin(), v1.end());
          printVevtor(v2);
        
          //n個elem方式構造   創建10個100的初始化操作
          vector<int>v3(10, 100);
          printVevtor(v3);
        
          //拷貝構造
          vector<int>v4(v3);
          printVevtor(v4);
        }
        
        int main()
        {
          //測試
          test01();
          
          system("pause");
          return 0;
        }
        

        運行結果:

        0 1 2 3 4 5 6 7 8 9
        0 1 2 3 4 5 6 7 8 9
        100 100 100 100 100 100 100 100 100 100
        100 100 100 100 100 100 100 100 100 100
        
      vector賦值操作
      • 作用:給vector容器進行賦值

      • 函數模型

        • vector& operator=(const vector&vec); //重載等號操作符
        • assign(beg,end); //將[beg,end]區間中的數據拷貝賦值給本身
        • assign(n,elem); //將n個elem拷貝賦值給本身
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        #include<vector>
        
        //vector賦值操作
        
        //打印函數
        void printVevtor(vector<int> &v)
        {
          for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
          {
            cout << *it << " ";
          }
          cout << endl;
        }
        
        void test01()
        {
          vector<int> v1;//默認構造  無參構造
        
          for (int i = 0; i < 10; i++)
          {
            v1.push_back(i);
          }
        
          printVevtor(v1);
        
          //賦值    operator=
          vector <int>v2;
          v2 = v1;
          printVevtor(v2);
        
          //assing
          vector<int>v3;
          v3.assign(v1.begin(), v1.end());
          printVevtor(v3);
        
          //n個elem 方式賦值
          vector<int>v4;
          v4.assign(10, 100);
          printVevtor(v4);
          
        }
        
        int main()
        {
          //測試
          test01();
          
          system("pause");
          return 0;
        }
        

        運行結果:

        0 1 2 3 4 5 6 7 8 9
        0 1 2 3 4 5 6 7 8 9
        0 1 2 3 4 5 6 7 8 9
        100 100 100 100 100 100 100 100 100 100
        
      • 總結:vector賦值方式比較簡單,使用operator=或者assign都可以

      vector容量和大小
      • 作用:對vector容器的容量和大小操作

      • 函數原型:

        • empty(); //判斷容器是否為空
        • capacity(); //容器的容量
        • size(); //返回容器中元素的個數
        • resize(int num); //重新指定容器的長度為num,若容器變長,則以默認值填充新位置。
          //如果容器變短,則末尾超出容器長度的元素被刪除
        • resize(int num,elem); //重新指定容器的長度為num,若容器變長,則以elem值填充新位置。
          //如果容器變短,則末尾超出容器長度的元素被刪除
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        #include<vector>
        
        //vector容器的容量和大小操作
        
        //打印函數
        void printVevtor(vector<int> &v)
        {
          for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
          {
            cout << *it << " ";
          }
          cout << endl;
        }
        
        void test01()
        {
          vector<int> v1;//默認構造  無參構造
        
          for (int i = 0; i < 10; i++)
          {
            v1.push_back(i);
          }
        
          printVevtor(v1);
        
          //判斷容器是否為空
          if (v1.empty())  //為真, 代表容器為空
          {
            cout << "v1為空" << endl;
          }
          else
          {
            cout << "v1不為空" << endl;
            cout << "v1的容量為:" << v1.capacity() << endl;
            cout << "v1的長度為:" << v1.size() << endl;
          }
        
          //重新指定大小
          v1.resize(15,20);
          printVevtor(v1);
        
          //重新指定大小
          v1.resize(5);
          printVevtor(v1);
        }
        
        int main()
        {
          //測試
          test01();
          
          system("pause");
          return 0;
        }
        

        運行結果:

        0 1 2 3 4 5 6 7 8 9
        v1不為空
        v1的容量為:13
        v1的長度為:10
        0 1 2 3 4 5 6 7 8 9 20 20 20 20 20
        0 1 2 3 4
        
      • 總結:

        • 判斷是否為空 --- empty
        • 返回元素個數 --- size
        • 返回容器容量 --- capacity
        • 重新指定大小 --- resize
      vector插入和刪除
      • 作用:對vector容器進行插入、刪除操作

      • 函數原型:

        • push_back(ele); //尾部插入元素ele
        • pop_back(); //刪除最后一個元素
        • insert(const_iterator pos,ele); //迭代器指向位置pos插入元素ele
        • insert(const_iterator pos,int count,ele); //迭代器指向位置pos插入count個元素ele
        • erase(const_iterator pos); //刪除迭代器指向的元素
        • erase(const_iterator start,const_iterator end); //刪除迭代器從start到end之間的元素
        • clear(); //刪除容器中所有元素
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        #include<vector>
        
        //vector容器的容量和大小操作
        
        //打印函數
        void printVevtor(vector<int> &v)
        {
          for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
          {
            cout << *it << " ";
          }
          cout << endl;
        }
        
        void test01()
        {
          vector<int> v1;//默認構造  無參構造
        
          //尾插法
          v1.push_back(10);
          v1.push_back(20);
          v1.push_back(30);
          v1.push_back(40);
          v1.push_back(50);
          //遍歷
          printVevtor(v1);
        
          //尾刪法
          v1.pop_back();
          printVevtor(v1);
        
          //插入  第一個參數是迭代器  begin()
          v1.insert(v1.begin(), 100);
          printVevtor(v1);
        
          //插入位置   重載版本
          v1.insert(v1.begin(), 2, 1000);
          printVevtor(v1);
        
          //刪除   第一個參數是迭代器
          v1.erase(v1.begin());
          printVevtor(v1);
        
          //刪除位置  重載版本  清空   ==    v1.clear();
          v1.erase(v1.begin(), v1.end());
          printVevtor(v1);
        }
        
        int main()
        {
          //測試
          test01();
          
          system("pause");
          return 0;
        }
        

        運行結果:

        10 20 30 40 50
        10 20 30 40
        100 10 20 30 40
        1000 1000 100 10 20 30 40
        1000 100 10 20 30 40
        [endl]  //因為最后一次輸出清楚了vector容器中元素,所以只產生了endl換行
        
      • 總結:
        尾插 --- push_back
        尾刪 --- pop_back
        插入 --- insert (位置迭代器)
        刪除 --- erase (位置迭代器)
        清空 --- clear

      vector數據存取
      • 作用:對vector中的數據的存取操作

      • 函數原型:

        • at(int idx); //返回索引|idx所指的數據
        • operator[]; //返回索引|idx所指的數據
        • front(); //返回容器中第一個數據元素
        • back(); //返回容器中最后一個數據元素
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        #include<vector>
        
        //vector容器  數據存取
        
        //打印函數
        void printVevtor(vector<int> &v)
        {
          for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
          {
            cout << *it << " ";
          }
          cout << endl;
        }
        
        void test01()
        {
          vector<int> v1;//默認構造  無參構造
        
          //插入數據
          for (int i = 0; i < 10; i++)
          {
            v1.push_back(i);
          }
        
          //利用函數訪問數組中元素
          printVevtor(v1);
        
          //利用[ ]中括號方式訪問數組中元素
          for (int i = 0; i < v1.size(); i++)
          {
            cout << v1[i] << " ";
          }
          cout << endl;
        
          //利用at方式訪問元素
          for (int i = 0; i < v1.size(); i++)
          {
            cout << v1.at(i) << " ";
          }
          cout << endl;
        
          //獲取第一個元素
          cout << "第一個元素為:" << v1.front() << endl;
        
          //獲取最后一個元素
          cout << "最后一個元素為:" << v1.back() << endl;
        }
        
        int main()
        {
          //測試
          test01();
          
          system("pause");
          return 0;
        }
        

        運行結果:

        0 1 2 3 4 5 6 7 8 9
        0 1 2 3 4 5 6 7 8 9
        0 1 2 3 4 5 6 7 8 9
        第一個元素為:0
        最后一個元素為:9
        
      • 總結:

        • 除了用迭代器獲取vector容器中元素,[]中括號和at也可以
        • frony返回容器第一個元素
        • back返回容器最后一個元素
      vector互換容器
      • 作用:

        • 實現兩個容器內元素進行互換
      • 函數原型

        • swap(vec); //將vec與本身的元素互換
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        #include<vector>
        
        //vector容器互換
        
        //打印函數
        void printVevtor(vector<int> &v)
        {
          for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
          {
            cout << *it << " ";
          }
          cout << endl;
        }
        
        //基本使用
        void test01()
        {
          vector<int> v1;//默認構造  無參構造
        
          //插入數據 for循環
          for (int i = 0; i < 10; i++)
          {
            v1.push_back(i);
          }
        
          printVevtor(v1);
        
          vector<int>v2;
        
          //插入數據 for循環
          for (int i = 10; i > 0; i--)
          {
            v2.push_back(i);
          }
        
          printVevtor(v2);
        
          cout << "交換后:" << endl;
        
          //交換數據
          v1.swap(v2);
          printVevtor(v1);
          printVevtor(v2);
        }
        
        //實際使用
        //巧用swap可以收縮內存空間
        void test02()
        {
          vector<int>v;
          for (int i = 0; i < 100000; i++)
          {
            v.push_back(i);
          }
        
          cout << endl;
          cout << "v的容量為:" << v.capacity() << endl;
          cout << "v的元素長度為:" << v.size() << endl;
          cout << endl;
        
          v.resize(3);   //重新指定元素長度
          cout << "v的容量為:" << v.capacity() << endl;
          cout << "v的元素長度為:" << v.size() << endl;
          cout << endl;
        
          //巧用swap收縮內存
          //vector<int>(v)為匿名對象  創建一個新的容器
          //利用swap做容器交換
          vector<int>(v).swap(v);
          cout << "v的容量為:" << v.capacity() << endl;
          cout << "v的元素長度為:" << v.size() << endl;
          cout << endl;
        }
        
        int main()
        {
          //測試
          test01();
          test02();
          
          system("pause");
          return 0;
        }
        

        運行結果:

        0 1 2 3 4 5 6 7 8 9
        10 9 8 7 6 5 4 3 2 1
        交換后:
        10 9 8 7 6 5 4 3 2 1
        0 1 2 3 4 5 6 7 8 9
        
        v的容量為:138255
        v的元素長度為:100000
        
        v的容量為:138255
        v的元素長度為:3
        
        v的容量為:3
        v的元素長度為:3
        
      • 總結:swap可以使兩個容器互換,可以達到實用的收縮內存效果

      vector預留空間
      • 作用:減少vector在動態擴展容量時的擴展次數

      • 函數原型:

        • reserve(int len); //容器預留len個元素長度,預留位置不初始化,元素不可訪問
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        #include<vector>
        
        //vector容器 預留空間
        
        void test01()
        {
          vector<int> v1;//默認構造  無參構造
        
          //利用reserve預留空間
          v1.reserve(100000);
        
          //統計開辟次數
          int num = 0;
          //指針
          int* p = NULL;
        
          //插入數據 for循環
          for (int i = 0; i < 100000; i++)
          {
            v1.push_back(i);
        
            //如果p指向不是v1[0]的地址,則p指向v1[0]的地址,開辟次數+1
            //因為開辟的空間不夠時,vector會重新開辟一塊更大的空間去存儲數據
            if (p != &v1[0])
            {
              //p指向v1[0]的地址 
              p = &v1[0];
              num++;
            }
          }
        cout << "開辟次數 num = " << num << endl;
        }
        
        int main()
        {
          //測試
          test01();
          
          system("pause");
          return 0;
        }
        

        運行結果:

        開辟次數 num = 1
        
      • 總結:如果數據量較大,可以一開始利用reserve預留空間

      deque容器

      • 功能:雙端數組,可以對頭端進行插入刪除操作
      • deque與vector區別:
        • vector對于頭部的插入刪除效率低,數據量越大,效率越低
        • deque相對而言,對頭部的插入刪除速度會比vector快
        • vector訪問元素時的速度會比deque快,這和兩者內部實現有關
      • deque內部工作原理:
        • deque內部有個中控器,維護每段緩沖區中的內容,緩沖區中存放真實數據
        • 中控器維護的是每個緩沖區的地址,使得使用deque時像一片連續的內存空間
      • deque容器的迭代器也是支持隨機訪問的
      deque構造函數
      • 函數原型:

        • dequedeqT; //默認構造形式
        • deque(beg,end); //構造函數將[beg,end]區間中的元素拷貝給本身
        • deque(n,elem); //構造函數將n個elem拷貝給自身
        • deque(const deque &deq); //拷貝構造函數
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        #include<deque>
        
        //deque 構造函數
        
        //打印函數
        void printDeque(const deque<int>& d)
        {
          for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
          {
            //容器中的數據不可以修改了
            //*it = 100;     //傳參處加const并且 迭代器前也加const  作用只讀不可寫
        
            cout << *it << " ";
          }
          cout << endl;
        }
        
        void test01()
        {
          deque<int>d1;
        
          //插入數據
          for (int i = 0; i < 10; i++)
          {
            d1.push_back(i);
          }
        
          //遍歷容器
          printDeque(d1); 
        
          //區間方式賦值
          deque<int>d2(d1.begin(), d1.end());
          printDeque(d2);
        
          //n個elem方式構造   創建10個100的初始化操作
          deque<int>d3(10, 100);
          printDeque(d3);
        
          //拷貝構造
          deque<int>d4(d3);
          printDeque(d4);
        }
        
        int main()
        {
          //測試
          test01();
          
          system("pause");
          return 0;
        }
        

        運行結果:

        0 1 2 3 4 5 6 7 8 9
        0 1 2 3 4 5 6 7 8 9
        100 100 100 100 100 100 100 100 100 100
        100 100 100 100 100 100 100 100 100 100
        
      • 總結:deque容器和vector容器的構造方式幾乎一致,靈活使用即可

      deque賦值操作
      • 作用:給deque容器進行賦值

      • 函數原型:

        • deque& operator=(const deque &deq); //重載等號操作符
        • assign(beg,end); //將[beg,end]區間中的數據拷貝賦值給本身
        • assing(n,elem); //將n個elem拷貝賦值給本身
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        #include<deque>
        
        //deque容器賦值操作
        
        //打印函數
        void printDeque(const deque<int>& d)
        {
          for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
          {
            //容器中的數據不可以修改了
            //*it = 100;     //傳參處加const并且 迭代器前也加const  作用只讀不可寫
        
            cout << *it << " ";
          }
          cout << endl;
        }
        
        void test01()
        {
          deque<int>d1;
        
          //插入數據
          for (int i = 0; i < 10; i++)
          {
            d1.push_back(i);
          }
        
          // operator= 賦值
          deque<int>d2;
          d2 = d1;
          printDeque(d2);
        
          //assign 賦值
          deque<int>d3;
          d3.assign(d1.begin(), d1.end());
          printDeque(d3);
        
          ////將n個elem拷貝賦值給本身
          deque<int>d4;
          d4.assign(10, 100);
          printDeque(d4);
        }
        
        int main()
        {
          //測試
          test01();
          
          system("pause");
          return 0;
        }
        

        運行結果:

        0 1 2 3 4 5 6 7 8 9
        0 1 2 3 4 5 6 7 8 9
        100 100 100 100 100 100 100 100 100 100
        
      • deque賦值操作與vector相同

      deque大小操作
      • 作用:對deque容器的大小進行操作

      • 函數原型:

        • deque.empty(); //判斷容器是否為空
        • deque.size(); //返回容器中元素的個數
        • deque.resize(num); //重新指定容器的長度為num,若容器變長,則以默認值填充新位置。
          //如果容器變短,則末尾超出容器長度的元素被刪除
        • deque.resize(num,elem); //重新指定容器的長度為num,若容器變長,則以elem值填充新位置。
          //如果容器變短,則末尾超出容器長度的元素被刪除
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        #include<deque>
        
        //deque容器 大小操作
        
        //打印函數
        void printDeque(const deque<int>& d)
        {
          for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
          {
            //容器中的數據不可以修改了
            //*it = 100;     //傳參處加const并且 迭代器前也加const  作用只讀不可寫
        
            cout << *it << " ";
          }
          cout << endl;
        }
        
        void test01()
        {
          deque<int>d1;
        
          //插入數據
          for (int i = 0; i < 10; i++)
          {
            d1.push_back(i);
          }
        
          //判斷deque容器是否為空
          if (d1.empty())
          {
            cout << "d1為空" << endl;
          }
          else
          {
            cout << "d1不為空" << endl;
            cout << "d1的大小為:" << d1.size() << endl;
            //deque容器沒有容量概念
          }
        
          //重新指定大小
          //d1.resize(15);
          //重載版本  指定填充數據
          d1.resize(15, 1);
          printDeque(d1);
        
          d1.resize(5);
          printDeque(d1);	
        }
        
        int main()
        {
          //測試
          test01();
          
          system("pause");
          return 0;
        }
        

        運行結果:

        d1不為空
        d1的大小為:10
        0 1 2 3 4 5 6 7 8 9 1 1 1 1 1
        0 1 2 3 4
        
      • 總結:

        • deque沒有容量的概念
        • 判斷是否為空 --- empty
        • 返回元素個數 --- size
        • 重新指定個數 --- resize
      deque插入和刪除
      • 作用:向deque容器中插入和刪除數據

      • 函數原型:
        兩端插入操作:

        • push_back(elem); //在容器尾部添加一個數據
        • push_front(elem); //在容器頭部插入一個數據
        • pop_back(); //刪除容器最后一個數據
        • pop_front(); //刪除容器第一個數據
          指定位置操作:
        • insert(pos,elem); //在pos位置插入一個elem元素的拷貝,返回新數據的位置
        • insert(pos,n,elem); //在pos位置插入n個elem數據,無返回值
        • insert(poe,beg,end); //在pos位置插入[beg,end]區間數據,無返回值
        • clear(); //清空容器所有數據
        • erase(beg,end); //刪除[beg,end]區間數據,返回下一個數據的位置
        • erase(pos); //刪除pos位置的數據,返回下一個數據的位置
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        #include<deque>
        
        //deque容器 大小操作
        
        //打印函數
        void printDeque(const deque<int>& d)
        {
          for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
          {
            //容器中的數據不可以修改了
            //*it = 100;     //傳參處加const并且 迭代器前也加const  作用只讀不可寫
        
            cout << *it << " ";
          }
          cout << endl;
        }
        
        void test01()
        {
          deque<int>d1;
        
          //尾部插入數據
          for (int i = 0; i < 5; i++)
          {
            d1.push_back(i);
          }
        
          printDeque(d1);
        
          //頭部插入數據
          for (int i = 0; i < 5; i++)
          {
            d1.push_front(i+10);
          }
          
          printDeque(d1);
        
          //尾刪
          d1.pop_back();
          printDeque(d1);
        
          //頭刪
          d1.pop_front();
          printDeque(d1);
        
          cout << endl;
        }
        
        void test02()
        {
          deque<int>d1;
          d1.push_back(10);
          d1.push_back(20);
          d1.push_front(100);
          d1.push_front(200);
        
          printDeque(d1);
        
          //insert插入
          d1.insert(d1.begin(), 1000);	//頭部插入一個1000
          printDeque(d1);
          //insert重載
          d1.insert(d1.begin(), 2, 100);	//頭部插入兩個100
          printDeque(d1);
        
          //按照區間方式插入
          deque<int>d2;
          d2.push_back(1);
          d2.push_back(2);
          d2.push_back(3);
        
          //1 2 3 100 100 1000 200 100 10 20
          d1.insert(d1.begin(), d2.begin(), d2.end());
          printDeque(d1);
          cout << endl;
        }
        
        void test03()
        {
          deque<int>d1;
          d1.push_back(10);
          d1.push_back(20);
          d1.push_front(100);
          d1.push_front(200);
        
          //刪除
          deque<int>::iterator it = d1.begin();
          it++;
          //頭部向右偏移刪除
          d1.erase(it);
          printDeque(d1);
        
          //按照區間方式刪除
          //clear與區間頭尾刪除方式一樣  都是清空數據。
          //數據清空  最后打印出來一個換行
          d1.clear();
          d1.erase(d1.begin(), d1.end());
          printDeque(d1);
        }
        
        int main()
        {
          //測試
          test01();
          test02();
          test03();
          
          system("pause");
          return 0;
        }
        

        運行結果:

        0 1 2 3 4
        14 13 12 11 10 0 1 2 3 4
        14 13 12 11 10 0 1 2 3
        13 12 11 10 0 1 2 3
        
        200 100 10 20
        1000 200 100 10 20
        100 100 1000 200 100 10 20
        1 2 3 100 100 1000 200 100 10 20
        
        200 10 20
        //最后因為清空了數據  只打印出來一個換行
        
      • 總結:

        • 插入和刪除提供的位置是迭代器!
        • 尾插 --- push_back
        • 尾刪 --- pop_back
        • 頭插 --- push_front
        • 頭刪 --- pop_front
      deque數據存取
      • 作用:對deque中的數據的存儲操作

      • 函數原型:

        • at(int idx); //返回索引|idx所指的數據
        • operator[]; //返回索引|idx所指的數據
        • front(); //返回容器中第一個數據元素
        • back(); //返回容器中最后一個數據元素
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        #include<deque>
        
        //deque容器 大小操作
        
        //打印函數
        void printDeque(const deque<int>& d)
        {
          for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
          {
            //容器中的數據不可以修改了
            //*it = 100;     //傳參處加const并且 迭代器前也加const  作用只讀不可寫
        
            cout << *it << " ";
          }
          cout << endl;
        }
        
        void test01()
        {
          deque<int>d1;
        
          //尾部插入數據
          for (int i = 0; i < 5; i++)
          {
            d1.push_back(i);
          }
        
          printDeque(d1);
        
          //通過[]中括號方式訪問元素
          for (int i = 0; i < d1.size(); i++)
          {
            cout << d1[i] << " ";
          }
          cout << endl;
          //通過at方式訪問元素
          for (int i = 0; i < d1.size(); i++)
          {
            cout << d1.at(i) << " ";
          }
          cout << endl;
        
          //訪問頭尾元素
          cout << "第一個元素為;" << d1.front() << endl;
          cout << "最后一個元素:" << d1.back() << endl;
        }
        
        int main()
        {
          //測試
          test01();
        
          system("pause");
          return 0;
        }
        

        運行結果:

        0 1 2 3 4
        0 1 2 3 4
        0 1 2 3 4
        第一個元素為;0
        最后一個元素:4
        
      • 總結:

        • 除了用迭代器獲取deque容器中元素,[]和at也可以
        • front返回容器第一個元素
        • back返回容器最后一個元素
      deque排序
      • 作用:利用算法實現對deque容器進行排序

      • 算法:

        • sort(iterator beg,iterator end) //對beg和end區間內元素進行排序
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        #include<deque>
        #include<algorithm>  //標準算法頭文件
        
        //deque容器 大小操作
        
        //打印函數
        void printDeque(const deque<int>& d)
        {
          for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
          {
            //容器中的數據不可以修改了
            //*it = 100;     //傳參處加const并且 迭代器前也加const  作用只讀不可寫
        
            cout << *it << " ";
          }
          cout << endl;
        }
        
        void test01()
        {
          deque<int>d1;
        
          //尾部插入數據
          for (int i = 0; i < 5; i++)
          {
            d1.push_back(i);
          }
        
          printDeque(d1);
        
          //頭部插入數據
          for (int i = 0; i < 5; i++)
          {
            d1.push_front(i);
          }
        
          printDeque(d1);
        
          //排序  默認排序規則  從小到達  升序
          //對于支持隨機訪問的迭代器的容器,都可以利用 sort 算法直接對其進行排序
          //vector容器也可以利用 sort 進行排序
          sort(d1.begin(), d1.end());
          cout << "排序后:" << endl;
          printDeque(d1);
        }
        
        int main()
        {
          //測試
          test01();
        
          system("pause");
          return 0;
        }
        

        運行結果:

        0 1 2 3 4
        4 3 2 1 0 0 1 2 3 4
        排序后:
        0 0 1 1 2 2 3 3 4 4
        
      • 總結:sort算法非常實用,使用時包含頭文件 algorithm 即可

      案例-評委打分

      • 案例描述:

        • 有5名選手:選手ABCDE,10個評委分別對每一個選手打分,去除最高分,去除最低分,取平均分
      • 實現步驟:

        • 創建五名選手,放到vector中
        • 遍歷vector容器,取出來每一個選手,執行for循環,可以把10個評分打分存到deque容器中
        • sort算法對deque容器中分數排序,去除最高喝最低分
        • deque容器遍歷一遍,累加總分
        • 獲取平均分
      • 示例:

        #include<iostream>
        using namespace std;
        #include<string>
        #include<deque>
        #include<algorithm>  //標準算法頭文件
        #include<vector>
        #include<ctime>
        
        //案例 評委打分
        //選手類
        class Person
        {
        public:
        
          Person(string name, int score)
          {
            this->m_Name = name;
            this->m_Score = score;
          }
        
          string m_Name;	//姓名
          int m_Score;	//平均分
        };
        
        void createPerson(vector<Person>&v)
        {
          for (int i = 0; i < 5; i++)
          {
            string nameSeed = "ABCDE";
            string name = "選手";
            name += nameSeed[i];
            int  score = 0;
            Person p(name, score);
            //將創建的Person對象  放入到容器中
            v.push_back(p);
          }
        }
        
        //打分
        void setScore(vector<Person>& v)
        {
          for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
          {
            //將評委的分數 放入到deque容器中
            deque<int>d;
            for (int i = 0; i < 10; i++)
            {
              int score = rand() % 41 + 60;
              d.push_back(score);
            }
        
            //排序
            sort(d.begin(),d.end());
        
            //去除最高和最低分
            d.pop_back(); 
            d.pop_front();
        
            //取平均分
            int sum = 0;
            for (deque<int>::iterator it = d.begin(); it != d.end(); it++)
            {
              sum += *it;  //累加每個評委的分數
            }
        
            //求平均分
            int avg = sum / d.size();
        
            //將平均分 賦值給選手身上
            it->m_Score = avg;
          }
        }
        
        //遍歷顯示
        void showScore(vector<Person>&v)
        {
          for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
          {
            cout << "選手:" << it->m_Name << "平均分:" << it->m_Score << endl;
          }
        }
        
        int main()
        {
          //隨機數種子
          srand((unsigned int)time(NULL));
          
          //1、創建5名選手
          //存放選手的容器
          vector<Person>v;
          createPerson(v);
        
          //2、給5名選手打分
          setScore(v);
          
          //3、顯示最后得分
          showScore(v);
        
          system("pause");
          return 0;
        }
        

        運行結果:

        //因為加入了隨機數  所以分數隨機  每次都不一樣
        選手:選手A平均分:81
        選手:選手B平均分:85
        選手:選手C平均分:72
        選手:選手D平均分:82
        選手:選手E平均分:88
        

      stack容器

      queue容器

      list容器

      set/multiset容器

      map/multimap容器

      STL-函數對象

      STL-常用算法

      主站蜘蛛池模板: 亚洲最大成人在线播放| 精品无码一区二区三区电影| 在线天堂中文www官网| 边添小泬边狠狠躁视频| 99久久精品久久久久久婷婷 | 无套内谢少妇毛片在线| 国产无套精品一区二区| 成av免费大片黄在线观看| 国产精品亚洲片夜色在线| 国产资源精品中文字幕| 午夜国产精品福利一二| 色吊丝一区二区中文字幕| 老师扒下内裤让我爽了一夜| 国产成人av免费观看| 夜爽8888视频在线观看| 成人午夜福利视频一区二区| 欧美日韩视频综合一区无弹窗| 日本一区二区三区专线| 亚洲av成人午夜福利| 日韩女同在线二区三区| 少妇无码一区二区三区免费 | 国产精品亚洲专区无码破解版| 高清日韩一区二区三区视频| 国产亚洲欧洲av综合一区二区三区| 老熟女高潮一区二区三区| 国产久久热这里只有精品| 深夜精品免费在线观看| 国产高跟黑色丝袜在线| 成人动漫综合网| 一区二区三区四区五区色| 少妇被粗大的猛烈进出69影院一| 精品无码三级在线观看视频| 午夜福利yw在线观看2020| 97国产精品人人爽人人做| 亚洲国产欧美一区二区好看电影| 女人与牲口性恔配视频免费| 男女性杂交内射女bbwxz| 亚洲色欲在线播放一区二区三区| 亚洲精品日韩精品久久| 亚洲国产成人无码av在线播放| 在线观看无码不卡av|