1. 程式人生 > 實用技巧 >c++筆記2

c++筆記2

一、 編譯環境及基本操作:
1.新建專案-win32控制檯應用程式-空專案
2.程式碼區
3.解決方案解析
project7_17_38:專案目錄(一個解決方案可以有多個專案(右鍵-設為啟動專案))
.sdf:分析檔案(每次開啟專案時建立,可以刪除)
.sln:解決方案(開啟專案,不可刪除)
.suo:使用者設定(可以刪除)
main:主函式,也稱為入口函式
一個專案只有1個主函式
一個解決方案可以有多個主函式
編譯:查詢是否有語法錯誤,生成.obj(目標)檔案,
生成-編譯(Ctrl+F7)
輸出視窗:檢視錯誤原因。
執行:檢視最終效果,將.obj檔案連結成.exe,
除錯-開始執行(Ctrl+F5)
引用標頭檔案:
#include “檔名”(引用自定義檔案):在專案目錄下查詢該檔案,找不到

再到系統目錄下查詢,再找不到就報錯。
#include <檔名>(引用系統檔案):在系統目錄下查詢該檔案,找不到就報錯。
註釋:不參與編譯,方便程式設計師閱讀程式碼。(70%)
單行註釋:以回車結束
多行註釋:/內容/ 快捷鍵:Ctrl+K+C
取消註釋:Ctrl+K+U
例:
/作者:**
日期:2018/7/17
版本:1.0.0*/
/*
常量:程式中不能改變的量。1,3.1,‘a’(字元),“abc”(字串)
變數:程式中可以改變的量,比如血量/等級/經驗值等。
定義:資料型別 變數名;
變數名:合法的識別符號。
1.由字母(a-z/A-Z)/數字(0-9)/下劃線(_)其中至少一者組成。
例如:a,a3,a_3
2.開頭不能是數字 比如3a(錯誤)
3.不能是關鍵字 比如:INt Int iNt(C++區分大小寫)
4.人為規定:顧名思義(hp/lv/exp/hero_lv)
二、 資料型別:
整型/浮點型/字元型/布林型
1.整型(用來表示整數):
int(普通整型):
在16位機器上佔2個位元組,
在32位以上機器上佔4個位元組。
short(短整型):佔2個位元組。
long(長整型):佔4個位元組。
long long(擴充套件性整型):佔8個位元組。
記憶體:以位元組為單位(變數佔記憶體)
機器碼:
以二進位制(0和1)儲存。
一個位元組用8位二進位制表示,
第一位表示符號位(0表示正,1表示負)
short(-2^15 ~ 2^15-1):最大值二進位制:01111111 11111111
=10000000 00000000 - 1 = 2^15 - 1
最小值:-2^15

2.進位制轉換
二進位制轉十進位制:從右往左,每一位上乘以2的n次方,
n從0開始,依次遞增1,求和。
十進位制轉二進位制:依次除以2,直到商為0,餘數從下往上讀。
m進位制轉十進位制:從右往左,每一位上乘以m的n次方,
n從0開始,依次遞增1,求和。
十進位制轉m進位制:依次除以m,直到商為0,餘數從下往上讀。
二進位制與八進位制:每3位二進位制對應1位八進位制。
二進位制與十六進位制:每4位二進位制對應1位十六進位制。
程式:十進位制:(0-9)
八進位制:(0-7):017 024
十六進位制:(0-9,a-f(A-F)):0xab 0x1a

3.浮點型(用來表示小數預設為double型別):
float(單精度):佔8個位元組
double(雙精度):佔8個位元組
long double(擴充套件性精度):佔16個位元組
2.%m.nf:n表示小數點位數
m表示字元寬度
如果實際字元寬度大於m,則正常顯示
如果小於,m為正數,在前面補空格,m為負數,在後面補空格
3.浮點數的表示形式:1.小數形式
2.指數形式 3e2=3*10^2
4.字元型:char:佔一個位元組。
既可以表示小整數(-128-127),又可以表示字元
每一個字元都對應一個整數,稱為ASCLL碼值。
1.字元型別在參與運算時,提升為整型
‘A’-‘C’=-3;
2.大小寫切換:大寫-小寫:ch+(‘a-‘A’)
3數字與字元的切換:0=‘o’:num+(‘o=0’)
4.轉義字元:\字元:佔1個位元組
\八進位制:\0
\十六進位制:\x
5布林型別(用來表示真假):
bool:佔1個位元組(true(1)和false(0))
1.布林型別參與運算時,提升為整型
2.一切非零的數都為真
#include 輸入輸出流庫
using namespace std;std是名稱空間名
引用名稱空間
1.全域性引用(可能會造成名稱空間汙染)
(當前檔案所有物件都可以使用)
2.區域性引用:名稱空間::
c語言的輸入輸出:scanf(),printf()
c++的輸入輸出:cin>>,cout<<

三、 運算子:

  1. 運算子運演算法則:
    算術運算子:+ - * / %(求餘/取模)
    1.不同精度的型別參與運算時,結果以精度高的為準。
    int + double = double
    2./:整型相除時,結果依然為整型。3/2 = 1
    3.%:運算子左右都必須為整型。
    判斷偶數/奇數:x%2
    拆分數字:198
    個位:198/1%10 = 8
    十位:198/10%10 = 9
    百位:198/100%10 = 1
    個位/十位/百位:a,b,c (c100+b10+c)
    棋牌:card
    1.花色:card / 0x10
    2.點數:card % 0x10
    紅桃3:0x13
    (花色:
    紅桃(0x11-0x1D)/黑桃(0x21-0x2D)/方塊(0x31-0x3D)/梅花(0x41-0x4D))
    2.點數:1-13
    3.大小王(0x51,0x52)
    紅桃3:0x13)
    自增自減運算子:
    ++:變數本身值+1;a++
    –:變數本身值-1;a–
    前置:++a:先自增再運算。
    後置:a++:先運算再自增。
    1.優先順序:後置>前置
    2.效率:前置>後置
    關係運算符(結果為bool型別):> < >= <= ==(等於) !=(不等於)
    邏輯運算子(式子左右為bool型別,結果為bool型別):(and or not)
    邏輯&&(且):a&&b;當a和b同時為真時,結果為真,否則為假。
    當a表示式為假時,則不計算b表示式。
    邏輯或||:a||b;當a和b同時為假時,結果為假,否則為真。
    當a表示式為真時,則不需要計算b表示式。
    邏輯非!:!a:a為真,!a為假,a為假,!a為真
    賦值運算子:=
    1.左邊必須為變數
    2.優先順序倒數第二
    3.與其他運算子結合使用:+= -= *= /= %=
    a+=1;a=a+1;
    a-=b;a=a-b;
    4.當表示式中有多個賦值運算子時,從右往左進行運算。

逗號運算子:表示式1,表示式2,…表示式n
1.逗號運算子的優先順序最低
2.運演算法則從左往右,最終結果為最後一個表示式的結果。

條件運算子(三目運算子):
?: a?b:c;當a為真時,執行b,否則執行c。

強轉:強制型別轉換
(要轉換的型別)
(int)量;

位運算子(速度最快):以二進位制的補碼參與運算。
原碼:將一個數轉化為二進位制。
反碼:正數的反碼是本身,負數的反碼是除
符號位外全部取反(0變1,1變0)
補碼:正數的補碼是本身,負數的補碼是
反碼+1.
補碼-原碼:補碼的補碼就是原碼。
運算流程:原碼-補碼(參與運算)-補碼(運算結果)-原碼(最終結果)
<<(左移):a<<1;a左移1位;a<<b;a左移b位;
將二進位制的補碼整體往左移n位,後面補0.(乘以2的n次方)

(右移):a>>1;
將二進位制的補碼整體往右移n位,正數補0,負數補1.

  

按位與&:a&b;(消除某些位數&0=0/保留某些位數&1)
將a和b的補碼從右往左一一對應,同1為1,否則為0.
按位或|:a|b;
將a和b的補碼從右往左一一對應,有1為1,否則為0.
按位異或:ab;
將a和b的補碼從右往左一一對應,相同為0,不同為1.
按位非:a
將a的補碼全部取反(0變1,1變0)
1.實現交換兩個數的值:
1.第三方變數
2.加法
3.異或
2.不使用算術運算子,如何判斷一個整數是奇數還是偶數?
(x&1) == 0?printf(“偶數”):printf(“奇數”);
3.不使用關係運算符,如何判斷一個整數是正數還是負數?
x>>31?printf(“負數等於-1”):printf(“正數等於0”);
4.如何判斷一個數二進位制的第n位是1還是0?
(x>>(n-1))&1
x&(1<<(n-1))
2. 運算子結合性

    1. 運算子優先順序
      優先順序:單目>雙目>三目(運算子左右的式子個數)
      算術運算子>(<< >>)>關係運算符>位運算子(&>^>|)

邏輯運算子(&&>||)>條件運算子>賦值運算子>逗號運算子

  

四、 語 句:
條件語句和迴圈語句
1、條件語句:
1.if語句:
if(條件1) 如果條件1為真,則執行語句1
{
語句1;簡單語句:只有一條語句,可以省略{}
複合語句:有多條語句,不可以省略{}
}
else當條件1為假時,執行語句2
{
語句2;
}

if(條件1) 如果條件1為真,則執行語句1
{
語句1;簡單語句:只有一條語句,可以省略{}
複合語句:有多條語句,不可以省略{}
}
else if(條件2) 如果條件2為真時,執行語句2
{
語句2;
}else 條件1和條件2都不滿足時,執行語句3
{
語句3;
}
if語句例項:

1 if(s>0&&s<=10)
2     if(s>=3&&s<=6)  3 4 5 6 
3         x=2;
4     else if(s>1||s>8)  2 7 8 9 10
5         x=3;
6     else  1
7         x=1;
8 else 
9     x=0;

1.條件語句只執行一次
2.elseif和else根據情況可寫可不寫,
elseif可以無限次新增,但else只有一個。
3.if語句只會進入一個分支。
4.else匹配原則:與之前最近的沒有匹配else的if匹配。

表示式:由常量/變數和運算子其中至少一種組成。
比如:a/a+3/3+2/3/a+b
常量表達式:由常量和運算子組成的式子。
1.計算表示式的值
2.與case後的常量表達式一一比較,如果相同,則執行case後的語句。
2.Switch(表示式)語句:
Switch(表示式)
{
Case 常量表達式1;
語句1;
Case 常量表達式2;
語句2;
Case 常量表達式n;
語句n;
}{}不能省略
注意:
1.case後的常量表達式不能相同
2.結束的標誌:1.}2.berak(跳出switch)
3.default與位置無關
例項:
輸入一個成績,判斷在0-59不及格–0-5
60-79:良好 --6 7
80以上:優秀 - 8-10

 1 int grade;
 2     cin >> grade;
 3     switch (grade / 10)
 4     {
 5     case 6:
 6     case 7:6/7表示式執行相同語句
 7         cout << "良好" << endl;
 8         break;
 9     case 8:
10     case 9:
11     case 10:
12         cout << "優秀" << endl;
13         break;
14     default:0-5
15         cout << "不及格" << endl;
16         break;
17     }

2、迴圈語句(可能執行多次):
1.for迴圈:
for(表達1;表達2;表達3)當所有表示式都省略時兩個分號都不能省略
{
迴圈體;迴圈體是簡單語句時可省略大括號{}不寫
}
表示式1:用來給迴圈變數初始化;int i=0; (可以省略)
表示式2:判斷迴圈跳出的條件;(可以省略,但要加入轉移語句,例如:break)
當條件為真,執行迴圈體,為假,跳出for迴圈。
表示式3:改變迴圈變數的值(步長);++i;i+=2;(可以省略)
For迴圈流程:

轉移語句:
Break:
1.在switch中,跳出switch語句
2.在迴圈語句中,跳出當前這一層迴圈;
Continue:跳出當前這一次迴圈,執行下一次迴圈
例項:
//99乘法表
//1
1=1 。。。。 19=9
//2
1=2 22=4
//3
1=3 32=6 33=9
//

 1 for (int i = 1; i <= 9; i++)
 2     {
 3         //列印一行
 4     for (int j = 1; j <= i; j++)
 5     {
 6         cout << i <<"*" << j << "=" << i * j << "\t";
 7         }
 8     //換行
 9     cout << endl;
10 }

2.While迴圈:
1.判斷表示式真假2當表示式為真時,執行迴圈體,否則跳出迴圈(反覆執行1.2)
While(表示式)
{
迴圈體;
}
例項:
int main()
{
//輸入一個整數,從個位起,輸出每一位上的數
//求逆數:1786-6871
//1786 //6871 =68710+1
//178 //687 =68
10+7
//17 //68 = 6*10+8
//1 //6

1 int num,newNum = 0;
2     cin >> num;
3     while (num != 0)
4     {
5         //cout << num % 10 << endl;//負數求餘:餘數符號:被除數符號決定//值:絕對值求餘 
6         newNum = newNum*10 + num % 10;     //-2 % 3 = -2   - 2 % -3 = -2;
7         num /= 10;
8     }
9     cout << newNum << endl;

3.do…while語句:
1執行一次迴圈體
2.判斷表示式的值
3.如果為真,則執行迴圈體,否則跳出迴圈體
4.反覆2和3
do
{
迴圈體;簡單和複合都不能省略

}while(表示式);({}和;都不能省略)
例項:

 1 int main()
 2 {
 3     //隨機種子:只需要寫一次
 4     srand(time(NULL));
 5     //9*9乘法表
 6     int i = 1;
 7     do 
 8     {
 9         int j = 1;
10         do
11         {
12             cout << i <<"*" << j << "=" << i * j << "\t";
13             j++;
14         } while (j <= i);
15         i++;
16         cout << endl;
17     } while (i <= 9);

五、 數 組:
陣列的定義:(陣列:是一類相同資料型別元素的集合)
資料型別 陣列名[陣列大小];
陣列大小必須為常量表達式:
1.常量與運算子結合的式子
2.const:只讀的,修飾變數 const int a;//a是隻讀的變數
1.必須初始化
2.被const所修飾的變數不能被修改
3.巨集定義 #define 巨集變數 值
#define size 5 //在使用size的地方全部用5代替
陣列的記憶體:陣列大小*每一個元素的所佔位元組
陣列的記憶體是連續的。如下圖所示:
0 1 2 3 4 8 12

陣列的初始化:{}

1 int n[5] = {1,2,3,4,5};

1.{},所有元素預設為0
2.{1,2,3},給部分元素賦值,其餘元素預設為0
3.{1,2,3,4,5},給全部元素賦值,可以省略陣列大小不寫

陣列賦值:給單個元素賦值。
陣列元素訪問:陣列名[下標];
//下標:任意表達式,從0開始,到陣列大小-1結束。
n[2];//第三個同學的數學成績,int型別的變數
n[2]++;
n[2]&&n[3];
n[2] = 3;
*/
示例:

 1 int num[5],count = 0;//count為計數器
 2     //int count, num[5];
 3     srand(time(NULL));
 4     //隨機5個數(0-100)存在陣列中,計算偶數的個數
 5     for (int i = 0; i < 5; i++)
 6     {
 7         num[i] = rand() % 101;//
 8         if (num[i] % 2 == 0)
 9         {
10             count++;
11         }
12     }
13 (c=getchar())!='\n'//

如何產生4個不同的數字?
1.判斷隨機的數與之前陣列中的數是否相等,
如果相等則重新隨機。

 1 for (i = 0; i<4; i++)
 2     {
 3         int x = rand() % 10;
 4         for (j = 0; j<i; j++) //檢查是否有重複
 5         {
 6             if (num[j] == x)
 7                 break;
 8         }
 9         if (j >= i) //沒重複
10             num[i] = x;
11         else
12             i--;
13     }

2.將10個數放到陣列中,隨機打亂,取前四個。
1.從鍵盤輸入十個數,存在陣列中,
求最大值和所對應的下標。
2.相鄰兩元素進行比較,將最大值移到最後一個位置。
//陣列越界:當陣列下標>=陣列大小時
//使用非法記憶體:編譯器沒有分配給該變數使用的記憶體
例項:

 1   int main()
 2     {
 3          //定義一個數字存放0-9之間的所有數字;
 4          int s[4];//定義陣列存放隨機打亂的num[]陣列的前四個
 5          srand(time(NULL));
 6          //把0-9之間數字放入陣列num[]中
 7          int num[10] = {0,1,2,3,4,5,6,7,8,9};
 8          for(int i= 0; i <=9; i++ )
 9          { cout << num[i] << "\t"; }
10          cout << endl;
11           //隨機打亂陣列num[]中的值,給兩個隨機下標,交換數值;
12          for (int k = 1; k < 1000; k++)
13          {        
14              int num1 = rand() % 10, num2=rand() % 10;
15              if (num1 != num2)
16     {
17                  num[num1] = num[num1]^ num[num2];
18                  num[num2] = num[num1] ^ num[num2];
19                  num[num1] = num[num1] ^ num[num2];
20              }
21          }
22      //for (int k = 0; k < 10; k++)//隨機打亂陣列num[]中的值,給一個隨機下標,從第一個陣列的值開始交換數值;
23      for (int j = 0; j <4; j++)//取前四個num[]的值並輸出
24      {
25          s[j] = num[j];
26          cout << s[j] << "\t" ;
27      }
28      cout << endl; 
29      return 0;
30 }

1.氣泡排序:(泡往上冒(從小到大)/泡往下冒(從大到小))
1.相鄰兩元素進行比較,如果前者>後者,則交換兩個數,
直到排出這一輪剩下的數中的最大(最小)值。
2.輪數:(陣列大小-1)次
3.外層迴圈是輪數,裡層迴圈是這一輪的比較次數
例項:

 1 for (int i = 1; i <= 9; i++)//控制輪數
 2     {
 3         //將相鄰兩個元素比較,把最大的移動到最後
 4         for (int j = 0; j <= 9 - i; j++)
 5         {
 6             if (num[j] >= num[j + 1])
 7             {
 8                 num[j] = num[j] ^ num[j + 1];
 9                 num[j + 1] = num[j] ^ num[j + 1];
10                 num[j] = num[j] ^ num[j + 1];
11             }
12         }
13     }

2.插入排序:(以從小到大為例)
1.將一個數插入到有序數列中,從後往前比,
如果大於某一個值,則位置確定,否則與前面的數交換,繼續比較。
2.輪數:把陣列看成只有1個數的有序數列,其餘陣列大小-1個數
當成是插入的數,輪數:陣列大小-1.

 1 //外層迴圈,控制輪數 
 2     for (int i = 1; i <= 9; i++)
 3     {   //裡層迴圈
 4         for (int j = i; j>0; j--)//j初始值:為插入元素的下標
 5         {
 6             if (num[j]>=num[j - 1])
 7             {
 8                 break;//跳出迴圈
 9             }
10             else
11             {
12                 num[j] = num[j] ^ num[j - 1];
13                 num[j-1] = num[j] ^ num[j - 1];
14                 num[j] = num[j] ^ num[j - 1];
15             }
16         }
17     }

3.選擇排序: (以從大到小為例)
1.每輪選出當前剩下的數中的最大數,與
第i個元素交換,i從0開始,每次+1.
1 5 2 3 4
第一輪:5 1 2 3 4
第二輪:5 4 2 3 1
第三輪:5 4 3 2 1
第四輪:5 4 3 2 1
2.輪數:陣列大小-1
例項:

 1 for (int i = 0; i <= 8; i++)
 2     {    //裡層迴圈
 3         int maxi_cur = i;//當前所剩數的最大值下標
 4         for (int j =i+1; j < 10; j++)
 5         {
 6             if (n[j]>n[maxi_cur])
 7             {
 8                 maxi_cur = j;
 9             }
10         }
11         //將最大值與第i個元素交換
12         if (maxi_cur != i)
13         {
14             n[i] = n[i] ^ n[maxi_cur];
15             n[maxi_cur] = n[i] ^ n[maxi_cur];
16             n[i] = n[i] ^ n[maxi_cur];
17         }
18     }

4.字元陣列: 元素型別為char型別
char 陣列名[陣列大小];
初始化
1.{}
2.字串,可以省略{}不寫 “abcd”
字串以’\0’結尾.
輸出字元陣列名:1.輸出字串,直到’\0’結束

5.二維陣列:多個一位陣列。
定義:資料型別 陣列名[行大小][列大小];
記憶體:行數列數單個元素所佔位元組;
二維陣列的記憶體是連續的,按行儲存;圖
二維陣列的初始化:
1.{}給部分元素/全部元素賦值時,可以省略行大小不寫
給部分元素賦值時:行大小以最接近元素個數的列數的倍數填充
2.{ {},{},{} };
元素的訪問:陣列名[行下標][列下標];
第三行第二列:a[2][1]
字元陣列:
char ch[3][6]={“abcdd”,”efgh”,”ijkl” }

1.字串拷貝
1.將src中的元素一一賦值給dest的元素,直到’\0’

1 1.for (int i = 0; (dest[i] = src[i]) != '\0'; i++);
2 2. int i = 0;
3       while ((dest[i] = src[i]) != '\0') 
4         i++;

2.庫函式實現:1.目的字串的陣列名 2.源字串的陣列名
strcpy(dest, src);//字串拷貝

2.字串連線
1.方法實現:
//1.找到要連線的位置
int i = 0;//i表示’\0’的下標
while (dest[i] != ‘\0’)
i++;
//2.連線
for (int j = 0;(dest[i + j] = src[j]) != ‘\0’; j++);
2庫函式實現:
1.被連線的字元陣列名 2.連線的字元陣列名
strcat(dest,src);//字串連線

3.字串比較 ························
1.方法實現:

 1 int value = 0;//表示兩個字串相等
 2     int i;
 3     for (i = 0; dest[i] != '\0' && src[i] != '\0'&&dest[i] == src[i]; i++);
 4     ///1.不相等 2.最後一個
 5     if (dest[i] < src[i])
 6         value = -1;
 7     else if (dest[i] > src[i])
 8         value = 1;
 9     cout << value << endl;
10 2. 庫函式實現:
11 strcmp("ab\0", "ab");

4.子串在母串中出現的次數

 1 char motStr[30] = "aaababaa";
 2     char subStr[5] = "aa";
 3     //1.遍歷母串
 4     int count = 0;
 5     for (int i = 0; motStr[i] != '\0';i++)
 6     {
 7         //2.遍歷子串
 8         for (int j = 0; motStr[i + j] == subStr[j]; j++)
 9         {
10             //判斷子串對應的j+1下標如果為'\0',則表示已經找到
11             if ('\0' == subStr[j + 1])
12             {
13                 count++;
14                 break;
15             }
16         }
17     }
18     cout << count << endl;
19     return 0;
20 }

楊輝三角:

 1 int main()
 2 {
 3     //楊輝三角
 4     int n[SIZE][SIZE];//SIZE:巨集變數
 5     for (int i = 0; i < SIZE;i++)
 6     {
 7         for (int j = 0;j <= i;j++)
 8         {
 9             //左右兩邊數都為1
10             if (0 == j || j == i)
11             {
12                 n[i][j] = 1;
13             }
14             else
15             {
16                 n[i][j] = n[i - 1][j - 1] + n[i - 1][j];
17             }
18         }
19     }
20 //列印輸出
21     for (int i = 0; i < SIZE; i++)
22     {
23         for (int j = 0; j <= i; j++)
24         {
25             cout << setw(3) << n[i][j];// setw(3)控制每個數字的寬度
26         }
27         cout << endl;
28     }

六、 函 數:
概念:對特定的功能進行封裝
定義:由返回值,函式名,引數表和函式體組成。
返回值型別 函式名(形式引數表)
{
函式體
}
輸出函式輸出字串“hello game”
void 空型別
1.確定返回值型別
2.確定函式名
3.確定引數表,引數表可以省略,但是括號不能省
4.引數表之中的引數用逗號隔開

呼叫:函式名(實參表)
注意:C++函式體內不能再定義其他函式,函式是並行的。
不能巢狀定義,可以巢狀呼叫
函式呼叫時:實參表和形參表型別,數量一一對應。
實參可以是常量,變數,表示式

  1. 作為函式語句
    Printf(“hello\n”)
  2. 函式表示式
    Int num=sum(a+3,3);
  3. 作為其他函式的實參;順序:從內往外呼叫;
    outputInt(sum(10, 9));
  4. 函式的呼叫流程:
    (呼叫的地方:主調函式 被呼叫的函式:被調函式)
  5. 從主調函式找到被調函式
  6. 系統給形參分配臨時記憶體,將實參的值拷貝(賦值)給形參
  7. 執行函式體,有返回值將返回值帶回主調函式
  8. 系統回收形參的臨時記憶體
  9. 回到主調函式

宣告:返回值型別 函式名(引數表);
寫在呼叫之前就可以
形參和實參的區別:
1、 形參出現在函式定義時,實參出現在函式呼叫時。
2、 形參只在函式呼叫之後被分配記憶體,呼叫完釋放形參記憶體。
3、形參的作用域只在函式內,出被調函式釋放,實參進入被調函式後無法使用
七、 指 針:
1.概念:為了方便訪問記憶體中的內容,給每一個記憶體單元編號,把這個編號稱為地址,也就是指標。
2.定義:(也是一種資料型別)
型別 指標名
(指標指向的型別 * )指標名;(:標註這個變數為指標)
//定義了一個int
型別的變數,變數名叫p
//p指向int型別的資料(p表示int型別資料的地址)
int* p;
//定義了一個int型別的變數,變數名叫p1
//p1指向int型別的資料(p1表示int型別資料的地址)
//該資料指向int型別的資料
intp1;
//定義了一個大小為5的陣列,陣列元素都為short型別
//陣列名為p2
//
short
p2[5];
3.指標的記憶體:
所有的指標都佔四個位元組;
4.指標的賦值:
&:取地址符:&(&變數)
解析引用符:只能跟指標(表示取指標指向的內容)
1.用指向型別的資料的地址賦值
int hp = 100;
//定義了一個int
型別的變數p-
//p指向int型別的資料hp(p表示int型別資料的地址)
int
p=&hp;
int* p1=p;

1    2.用相同型別的指標賦值
2       int* p1=p;
3    3.直接用地址賦值
4       int* p4 = (int*)0x12abcd89;
5    4.用字串給字元指標賦值
6       char* p = "abcd";
7    5.用陣列名賦值

int n[5];
int* p4 = n;
6.指標沒有明確指向時,賦值為空
&,可以抵消,&不能抵消.
解析引用符:取內容位元組數 = 指標指向的資料的位元組數
short
:short int
:

使用cout輸出char型時,
從這個地址開始直到\0的字串全部輸出.
指標練習及解析:
一、
int a = 3;//定義了一個名為a的int型變數,並給它賦初值為3
int
p = &a;//定義了一個int*型的指標p,p指向a

 1 *p = 4;//把整數4賦值給p指向的內容(實際上為a),p的指向的a變為4
 2 cout << "a=" <<a << endl;//輸出a=4
 3 (*p)++;//*p指p指向的a,所以(*p)++相當於a++,因此a=4++=5
 4 int b = 4;//定義了一個名為b的int型變數,並給它賦初值為4
 5 int c = b**p;//定義了一個名為c的int型變數,並給它賦初值為b**p;
 6 //b**p=b*(*p),*p指p指向的a,而a=5,所以b**p=b*5=4*5=20;
 7 cout << "*p=" << *p << endl;//輸出*p=5;*p指p指向的a,即a=5;
 8 cout << "a=" << a << endl;//輸出a,a=5;
 9 cout << b << c << endl;//輸出b,b=4;輸出c,c=20;
10 
11 int** p1 = &p;//定義了一個名為p1的int**型變數,p1指向p;
12 **p1 = c++;/*把c的值賦給**p1指向的內容,即*p指向的內容,即a,所以a=c=20;然後c++ c=21;*/
13 *p1 = &b;//把b的地址賦給*p1指向的內容,即p指向b;
14 (**p1)++;//**p1指向的內容自增,即b自增,即b=5;
15 p = &c;//把c的地址賦給指標p,p指向c;
16 *p = a***p1;//把a***p1賦值給*p指向的內容,即c,
17 //a***p1=a**(*p1)=a**p=a*(*p)=a*c=20*21=420;
18 cout << a << b << c << endl;//輸出a,b,c的值,分別為:20 5 420
19 cout << *p1 << endl;//輸出C的地址;p=&c
20 cout << &c << endl;//驗證*p1是否是c的地址
21 cout << *p << endl;//輸出*p指向的內容,即c,所以輸出420

二、
char ch[5] = “abcd”; //定義了一個大小為5的char型陣列ch,並給它的元素賦值為abcd;
char* p = &ch[1];//定義了一個char型的指標p,p指向ch[1];
charp1 = &p;//定義了一個char型的指標p1,p1指向p;
cout <<p1 << endl;//輸出p1指向的內容,即p,p為char
型,所以輸出:bcd
ch = (p1)++;//把p1指向的內容賦值給ch指向的內容,然後**p1指向的內容自增
//*ch指向ch[0]:a;**p1指向ch[1],所以,ch[0]=ch[1]=b;ch[1]++=c;
*p1 = &ch[3];*p1指向p,p = &ch[3];p指向ch[3]
cout << *p + 3 << endl;//*p指向ch[3],所以輸出‘d’+3=100+3=103
*p1 = &ch[2];//*p1指向p,p = &ch[2];p指向ch[2]
cout << *p1 << endl;//p1指向p,p為char型,所以輸出cd
(*p)++;//p指向的內容為ch[2];所以ch[2]=c++=d;
cout <<p << endl;//輸出p指向的內容,即ch[2],即d
cout << ch[2] << endl;//輸出ch[2],即d
cout << ch[2] + 1 << endl;//輸出ch[2]+1,即d+1,提升為整型,所以輸出100+1=101;
cout << p << endl;//應為p為char
型,並且p指向ch[2],所以輸出dd

三、
char ch[5] = “ijkl”;//定義了一個大小為5的char型陣列ch,並給它的元素賦值為ijkl;
char* chArray[3] = { ch, &ch[1], &ch[3] };//定義了一個大小為2的char型陣列chArray,
//並且它的元素分別指向ch, &ch[1], &ch[3];
char** pArray = chArray;//定義了一個char**型變數pArray ,pArray指向chArray陣列的首元素;
int i = 1;//定義了一個int型變數i,並給它賦值為1;
ch[i++] = (**pArray) + 3;//把(**pArray) + 3賦值給ch[i++],ch[i++]即為ch[1],
//,**pArray指向的內容為ch[0];ch[1]=ch[0]+3=l;並且i++,i=2
pArray = &chArray[2];//把chArray[2]的地址賦值給pArray,pArray指向chArray[2];
cout <<pArray << endl;//輸出pArray指向的內容,即&ch[3],為char
型,所以輸出l
cout << &ch[i] << endl;//輸出&ch[i],i=2;所以輸出&ch[2],又因為&ch[2]為char型,所以輸出kl
pArray = &ch[0];//把ch[0]的地址賦給pArray指向的內容,即chArray[2]指向ch[0];
(**pArray)–;//指向的內容為ch[0],所以ch[0]–,ch[0]=h;
cout <<pArray << endl;//輸出pArray內容,即ch[0],所以輸出h
pArray = &chArray[1];//把chArray[1]的地址賦給pArray,pArray指向chArray[1];
cout << **pArray << endl;//**pArray 指向的內容為chArray[1],所以輸出chArray[1]
//chArray[1]為char
型,所以輸出jkl
cout << ch << endl;//ch為char*型,所以輸出hjkl
cout << **pArray + 5 << endl;//*pArray指向ch[1],所以輸出’j’+5,提升為整型;所以等於113
cout << (pArray)[1] << endl;//pArray所指內容向右偏移1,所以輸出k
5.指標的運算:
1.加減法:指標加上或者減去一個整數n,表示指標偏移n個單位.
(單位 = 指標指向的型別所佔位元組)
int
p;
p+1;//p+1偏移一個單位 = 4個位元組
short
p;
p-1;//p-1 = 向左4個位元組
2.指標 - 指標:相差的單位數
3.指標的自增自減:
p++;
p–;指標本身偏移1個單位;
4.指標[]:p[1],p[-1];
以p為首地址的第n+1個元素;
p[n] = *(p+n);

陣列名和指標除了自增自減和賦值外,無區別.

大端儲存(與閱讀習慣一致):資料的高位存在記憶體的低地址,
資料的低位存在記憶體的高地址.(讀取資料:低地址 - 高地址)
小端儲存(win32)(與邏輯習慣一致):資料的高位存在記憶體的高地址,
資料的低位存在記憶體的低地址.(讀取資料:高地址 - 低地址)

nullptr:強指標(只能賦值給指標)
6.陣列指標:

陣列指標:指向陣列的指標.
1.陣列指標的定義:
元素型別(*陣列指標名)[列數n];指標指向列數為n的一維陣列
陣列指標的賦值:
1.一維陣列名的地址
2.二維陣列名

2.陣列指標的偏移:
p+1:偏移一行(1個單位 = 每個元素所佔位元組 * 列數)
p++:
p[n] =(p+n)
指標陣列:陣列的元素為指標.
char
n[5];
含義上,n是&n[0]
值:n = n[0] = &n[0][0]
/cout << n << endl;
cout << n[0] << endl;
cout << &n[0][0] << endl;
/

1 定義了一個數組指標p,p指向列數為4,
2 元素型別為int型的一維陣列.
3 n是{n[0],n[1],n[2]}的陣列名,n等於&n[0]
4 n[0]是{n[0][0],n[0][1],n[0][2],n[0][3]}的陣列名
5 n[0]是&n[0][0]
6 int(*p)[4] = n;//n等於&n[0]

定義了一個數組指標p1,p1指向列數為5,元素型別為char型的一維陣列
char
(*p1)[5];
1.陣列:陣列大小與陣列名不用括號分開
2.指標:指向的型別 * 指標名
定義了一個指標p2,指標指向陣列指標
該陣列指標指向列數為4,元素型別為int型別的一維陣列
int(**p2)[4] = &p;
陣列:元素型別 陣列名[陣列大小]
定義了一個大小為5的陣列p3,
元素型別為陣列指標型別,該陣列指標
指向列數為4,元素型別為int型的一維陣列
int(*p3[5])[4] = {p,p,p,p,p};

1 含義:n[0]是第一行的陣列名,是&n[0][0],為int*2 cout << n[0] << endl;
3 cout << &n[0][0] << endl;
4 int* p = &n[0][0];

7.多維陣列:
資料型別 陣列名[維數1][ 維數2][]……[ 維數n];
int n[3][4][5];
指向一維陣列及以上的指標都是陣列指標.
元素型別 (指標名)[維數2]…[維數n]
typedef:給型別取別名。(寫在函式外,一般寫在函式前)
typedef 型別 別名;
觀察什麼型別可以將typedef去掉
void
:空指標型別(不確定型別的指標)
1.可以指向任意型別的資料
2.因為沒有明確的指向,所以不能偏移和取內容。

指標與const的結合:
(非const可以給const賦值,const不能直接給非const賦值)
1.常量指標:表示指標指向一個常量
(const 指向型別)指標名;const intn;
(指向型別 const)指標名;int constn;
常量指標不能改變指向的內容,但是可以改變指向。
2.指標常量:指標本身被const修飾的變數,是隻讀的
指向型別* const 指標名
1.必須初始化
2.指標常量不能改變指向,但是可以改變指向的內容
3.常量指標常量:
1.必須初始化
2.既不能改變指向,也不能改變指向的內容

區分常量指標和指標常量:
const在之前是常量指標,在後就是指標常量

8.記憶體區域的劃分:
1.常量區(不能被修改):
常量(1,100,1.1,‘a’,“abcd”),字串
程式開始時系統分配記憶體,程式結束時系統自動回收記憶體.
2.全域性區(靜態儲存區):
全域性變數(定義在函式外的變數)和
靜態(static)變數(static 型別 變數名;)
1.只初始化一次,預設為0
2.記憶體只有一份
程式開始時系統分配記憶體,程式結束時系統自動回收記憶體.

3.棧區:區域性變數(定義在函式內的變數)
進入函式時系統分配記憶體,函式結束時系統回收記憶體.

4.堆區:由程式設計師手動申請,手動釋放.(申請-釋放-置空)
C語言(函式):
1.形參:申請的位元組數 2.返回值:申請記憶體的首地址
void *malloc( size_t size );
函式返回一個指向num 陣列空間,
每一陣列元素的大小為size。
如果錯誤發生返回NULL。
void *calloc( size_t num, size_t size );
釋放記憶體:free(記憶體首地址);

C++(運算子):
int* p = new int;//返回申請記憶體的首地址
int* p = new int(元素初始化);//給這段記憶體存入值
int* p = new int[陣列大小];//申請連續的記憶體

delete 記憶體的首地址;//釋放1個指向大小的記憶體
delete[] 記憶體的首地址;//釋放一段連續的記憶體
申請:

int** pMap = new int*[h];//申請記憶體(動態二維陣列)
for (int i = 0; i < h; i++)
{
pMap[i] = new int[w];
}

釋放:

1 for (int i = 0; i < h; i++)//釋放記憶體
2           {
3              delete[] pMap[i];
4              pMap[i] = NULL;
5           }
6          delete[] pMap;
7          pMap = NULL;

全域性變數和全域性static變數區別:
1.生存週期相同,從程式開始分配記憶體,程式結束回收記憶體.
2.作用域不同,全域性變數可以作用於所有檔案,需要extern宣告
全域性static變數只能作用於當前所在檔案.

區域性變數和區域性static變數區別:
1.生存週期不同,區域性變數進入函式時系統分配記憶體,函式結束時系統回收記憶體.
區域性static變數程式開始時系統分配記憶體,程式結束時系統自動回收記憶體.
2.作用域相同.(函式內)

9.指標補充
1.記憶體洩漏:記憶體沒有釋放,指標改變了指向
2.野指標(壞指標):釋放了記憶體,但指標沒有置空

使用指標:
1.指標必須有指向(沒有賦值和指向NULL為兩個概念)
2.陣列越界

引用(實質上是指標)的定義:給變數取別名.
&:引用符
型別& 變數名;例如:int& a;
1.必須初始化
2.不能改變引用的物件
常引用(不能改變被引用物件的值):引用的是一個常量.
const 型別& 變數名;

指標和引用的區別:
1.引用必須初始化,指標可以不初始化.
2.引用不能賦值為空,指標可以賦值為空.
3.引用與被引用物件共享一段記憶體,指標有獨立的記憶體.
4.引用不能改變引用的物件,指標可以改變指向.

動態一維陣列:手動申請了5個int型別大小的記憶體,記憶體連續
p指向記憶體的第一個元素

1 int* p = new int[5];
2     delete[] p;
3     p = NULL;
4     cout << *p << endl;
5     p = new int[2];
6     delete[] p;
7     p = NULL;

動態申請二維陣列記憶體(行與行之間記憶體不一定連續)
申請3行5列
1.申請3個int*型別大小的記憶體,
儲存之後的每一行的首地址

 1 int** p1 = new int*[3];
 2     for (int i = 0; i < 3; i++)
 3     {
 4         p1[i] = new int[5];
 5     }
 6     for (int i = 0; i < 3; i++)
 7     {
 8         delete[] p1[i];
 9         p1[i] = NULL;
10     }
11     delete[] p1;
12     p1 = NULL;

八、標頭檔案:
1.檔案管理:
標頭檔案-右鍵-新增新建項-.h檔案
2.引用自定義檔案:用""引用
引用標頭檔案的意義:整個標頭檔案替換到引用處
3.專案資料夾分類
引用帶路徑的標頭檔案:/
引用根目錄上一層的路徑:…
4.篩選器:方便在解決方案面板管理
(保持與外部資料夾同步)
注意:
1.將函式的宣告寫在.h檔案中,將函式的定義寫在.cpp檔案中
(函式的宣告可以多次,函式的定義只能一次)
(最好.h和.cpp檔案同名)
2.全域性變數的宣告也放在.h檔案中,定義寫在.cpp檔案中
(extern時給變數賦值變為定義,可能報重定義錯誤)
3.巨集定義可以寫在標頭檔案中,定義多次不會報錯,
後面的定義覆蓋前面的定義.

1.標頭檔案不進行編譯,原始檔分別編譯
2.無法解析的外部符號:
函式:只寫了宣告沒有寫定義
無法解析的外部符號
變數:只寫了宣告沒有寫定義

九、函式補充:
函式的形參:
1.形參為陣列時,會被弱化成指標
一維陣列:
1.int n[10],10不代表陣列的大小.
2.int n[];
3.int n[],int size;//size表示陣列的大小
4.int* n;
5.int* n,int size;//推薦
2.二維陣列:被弱化成陣列指標
1.int n[3][10];
2.int n[][10];//不能省略列大小
3.int n[][10],int row;//row指行大小
4.int(*p)[10];//
5.int(*p)[10],int row;//推薦,加上行大小

3.形參為被const修飾時:
1.修飾普通型別,防止形參被修改
2.修飾指標時,常量指標(防止指向內容被改變)
3.修飾引用時,常引用(防止被引用物件的值被改變)

返回值:不能返回棧區的地址或者引用.
1.返回值為指標:
2.返回值為引用:既可以作為左值,又可以作為右值.
作為左值時:被引用物件被賦值.
作為右值時:1.給普通型別賦值:將值賦值給變數
2.給引用型別賦值時:該引用型別也引用該變數
特殊情況:返回常引用(防止通過返回值修改被引用物件的值)

函式:
優點:可以重複使用,節省空間,使結構更清晰.
缺點:查詢函式,時間上的消耗.

短小(沒有迴圈)且頻繁使用的函式:
1.C語言:巨集定義函式(巨集替換)
#define 巨集定義名(形參表:不需要型別) 函式體;
1.(巨集替換),整體思維,注意()
2.不進行型別檢測
3.傳遞型別
4.巨集定義函式有多行時,每一行末尾用\結束
(\緊跟換行符)

2.C++:行內函數(函式體替換到函式呼叫處)
以空間換取時間的函式.
在函式定義前面加上inline關鍵字.
4.函式過載:
函式名相同,形參不同.(型別/順序/個數其中至少一者不同)
1.引數傳遞時,只能低精度往高精度轉化,否則進行強轉
2.返回值型別不同,不能稱為過載.
報錯:無法過載返回型別區分的函式.
3.僅引數名不同,不能稱為過載.
函式在C++內部編譯:函式名_形參型別1_形參型別2
sum_int_int
C語言不支援過載.

5.函式預設(引數預設):形參有預設的實參值.
形參型別 變數名 = 預設值;
預設順序:從右往左;
引數預設寫在函式宣告中;
int sum(int a = 1,int b = 2);//正確
int sum(int a,int b = 2);//正確
int sum(int a = 1,int b);//錯誤
1.不傳遞預設實參,以預設值為準
2.傳遞實參,實際實參覆蓋預設實參

6.函式指標:指標指向一個函式.(函式佔記憶體)
函式指標(是一種資料型別)的定義:
返回值型別 (*函式指標名)(形參表(不需要變數名));
//pfunc指向返回值型別為int型別,形參為int,int的函式.
int(*pfunc)(int,int);
指標函式:返回值為指標的函式.

賦值:
1.&函式名(都表示指向函式)
2.函式名(推薦)

使用函式指標呼叫函式:
函式名(實參表);
1.(*函式指標)(實參表);
2.函式指標(實參表);(推薦)

7.const的至少三種用法:
 指標常量:int* const p;//必須初始化
 常量指標:const int* p;
 常量指標常量:const int* const p;
 常引用:const int& a = b;
 const修飾普通型別的變數:表示只讀
8.遞迴
1.斐波那契數列:1 1 2 3 5 8 13 21…
求第n項.
fab(n) = fab(n-2)+fab(n-1)
2.求!n:n的階乘
3.猴子吃桃:第一天猴子吃了桃子總數的一半加1個,
第二天吃了剩下桃子數的一半加1個,按照這種吃法,
第10天時,發現只剩一個桃子,請問第一天有多少桃子?
第二天 = 第一天/2 - 1
第一天 = (第二天 + 1)*2
peach(day) = (peach(day+1) + 1) * 2;
遞迴:函式直接或者間接的呼叫自身.
遞推:函式呼叫的過程.
回推:返回的過程.
當遞迴跳不出來時,棧溢位(stack overflow)
1.找規律 fab(n) = fab(n-2)+fab(n-1)
2.找跳出條件

 1 if (1 == n || 2 == n)
 2 return 1;
 3 //mul(n) = n*mul(n - 1);
 4 int peach(int day)
 5 {
 6     if (10 == day)
 7         return 1;
 8     return (peach(day + 1) + 1) * 2;
 9 }
10 int mul(int n)
11 {
12     跳出條件
13     if (1 == n)
14         return 1;
15     return n * mul(n - 1);
16 }
17 int fab(int n)
18 {
19     //跳出條件
20     if (1 == n || 2 == n)
21         return 1;
22     //規律
23     return fab(n - 1) + fab(n - 2);
24 }
25 
26 int fab(int n)
27 {
28     //如果n為1和2,返回1
29     if (1 == n || 2 == n)
30         return 1;
31     //第n項等於前兩項之和
32     int a = 1, b = 1;//a表示n的前兩項,b表示n的前一項
33     for (int i = 3; i <= n;i++)
34     {
35         int t = b;    
36         b = a + b;
37         a = t;
38     }
39     return b;
40 }

函式:1.不能出現功能重複的程式碼
2.不要通過修改資料

專案三部曲:
1.初始化:資料的準備(執行一次)
2.更新:資料的改變(迴圈)
3.繪製:最終效果的顯示(迴圈)

1 //防止標頭檔案被重複引用
2 #ifndef _HERO_ //--如果沒有定義
3 #define _HERO_ //--定義
4 *****
5 #endif

十、自定義型別:
結構體/聯合/列舉(由基本資料型別組成)

  1. 結構體:
    概念:一類具有相同屬性和行為的事物的封裝
    英雄:屬性:血量/等級/藍/經驗…
    行為:移動/攻擊…
    騎車:屬性:顏色/型號/速度…
    行為:移動/加速/停止…
    1.結構體的定義:
    //struct:關鍵字,表示是一個結構體

struct 結構體型別名//型別名首字母大寫
{
資料成員1;//資料型別+變數名
資料成員2;
資料成員n;

}
2.記憶體:結構體對齊
以所有型別中最大記憶體為單位分配位元組.
4+4+4+4(hp)+4(lv)=20
定義結構體時,記憶體從小到大定義成員
3.結構體變數的定義:
結構體型別名+變數名;
4.初始化:{}//按照成員的順序一一賦值,中間用逗號隔開
5.賦值:
1.{}
2.單獨給成員賦值:
成員訪問:成員選擇符(.)
6.結構體型別指標的定義
結構體型別 * 指標名
Hreo* p=&hero;//p指向hero
通過結構體型別指標訪問成員:1.(*p).lv
2.成員選擇符(->):指標->成員名
7.結構體陣列:
結構體型別 陣列名[陣列大小];

  1. 聯合型別
    定義:

    union 聯合型別名
    {
    聯合成員1;//資料型別+變數名
    聯合成員2;
    };

記憶體:記憶體對齊(所有成員共享一段記憶體)

  1. 列舉型別:(表示狀態值.)
    方向的狀態:上下左右
    遊戲狀態:開始/暫停/遊戲中/結束
    物品型別:藥品/裝備
    定義:

    enum 列舉型別
    {
    狀態值1,//UP(推薦)/up
    狀態值2,

    狀態值n
    };

記憶體:列舉變數為一個int型別的大小,
每一個列舉狀態值都對應一個整數,
如果沒有給列舉狀態賦值,從0開始,依次+1.
如果給其中某個列舉狀態賦值,從此之後的所有狀態:基礎上+1.
例如:

1 enum Dir
2 {
3     UP,
4     DOWN,
5     LEFT,
6     RIGHT
7 };
  1. 讀取/儲存檔案:
    1.儲存檔案:

    void saveFile(int** pMap, int row, int line, int level)
    {
    //1.檔案路徑2.模式寫入wb+ 讀取rb+
    //printf(“map_%d.txt”, level);
    char fileName[20];
    sprintf(fileName, “Map/map_%d.txt”, level);//printf輸出到控制檯,sprintf輸出到字元陣列中
    FILE* pfile = fopen(fileName, “wb+”);//開啟1個檔案,如果沒有,則自動建立
    //寫入:1.被寫入的資料的首地址 2.1個數據的大小
    //3.資料的個數4.FILE*
    for (int i = 0; i < row; i++)
    {
    //fwrite會偏移count個size大小的記憶體
    fwrite(pMap[i], sizeof(int), line, pfile);
    }
    //關閉檔案
    fclose(pfile);
    }

2.開啟(讀取)檔案:

 1 void readFile(int(*pMap)[10], int row, int line, int level)
 2 {
 3     char fileName[20];
 4     sprintf(fileName, "Map/map_%d.txt", level);
 5     //1.開啟檔案
 6     FILE* pfile = fopen(fileName, "rb+");
 7     fread(pMap, sizeof(int), row * line, pfile);
 8     fclose(pfile);
 9 }
10 //exit(0);//退出程式

十一、類:

  1. C語言:面向過程,以函式為核心.
  2. C++語言:面向物件,以類為核心.

1.類的概念: 一類具有相同屬性和行為的事物的封裝.
2.類的特性: 封裝/繼承/多型
//宣告和定義各一個檔案(.h和.cpp同名)
3.類的定義:

 1 class 類名
 2 {
 3     成員1;//資料成員和成員函式
 4     成員2;
 5 };
 6 
 7 class Hero //Hero是一種資料型別
 8 {
 9 public://:冒號
10      Hero();//預設普通建構函式
11      Hero(int hp);//帶參建構函式
12      Hero(const Hero& other);//拷貝建構函式
13 private:
14     int lv;
15     int exp;
16 public:
17     int hp;
18     void pk();
19     void die();
20 };

4.struct和class的區別:
1.struct是C語言的,而class是C++的.
在C++中struct和class都能用,
在C語言中只能用struct.
2.成員訪問許可權:
struct預設為public,
class預設為private.
訪問許可權:
public:公有的,成員可以在類中和類外訪問.
protected:保護的,成員可以在類中和子類中訪問.
private:私有的,成員只能在類中訪問.(預設)
1.三種訪問許可權不一定全部寫.
2.資料成員一般指定為私有的.
成員函式一般指定為公有的.
3.重複訪問許可權不報錯

5.類的物件(變數)建立:
1.類名 物件名;Hero hero;
2.new 類名;new Hero;

普通全域性函式和類的成員函式的區別:
類的成員函式必須通過物件呼叫.

每一個成員函式中:this指標(可省略不寫)
this指向當前呼叫函式的物件
6.類的四大預設成員函式:
1.普通建構函式(預設:沒有形參)
1.沒有返回值型別
2.函式名與類名完全相同
3.普通建構函式可以過載(普通建構函式可以有多個)
呼叫:給物件分配記憶體時呼叫.
(1.類名 物件名; 2.new 類名;)
呼叫無參:1.類名 物件名; 2.new 類名; 3.new 類名();
呼叫帶參:1.類名 物件名(實參表);
2.new 類名(實參表);
//預設普通建構函式(無參建構函式)的定義

1 Hero::Hero()
2 {
3     cout << "呼叫了無參建構函式" << endl;
4 }        
5 Hero::Hero(int hp)
6 {
7     cout << "呼叫了帶參建構函式" << endl;
8 }

2.拷貝建構函式(複製建構函式)
1.沒有返回值型別
2.函式名與類名相同
3.形參為const 類名& 物件名;
呼叫:1.用類的物件給另一個物件初始化時;
Hero hero1 = hero;//定義時賦值
2.顯示呼叫拷貝建構函式;
Hero hero(hero1);
const Hero& other = hero1;
3.形參為類的物件時:將實參的值拷貝給形參
void test(Hero hero);
4.返回值為類的物件時
Hero::Hero(const Hero& other)
{
cout << “呼叫了拷貝建構函式” << endl;
}

當任意建構函式被顯示給出時,
不能呼叫系統預設的無參建構函式,
也需要顯示給出.

3.賦值函式:
類名& operator=(const 類名& other);
A& operator=(const A& other);
呼叫:用一個類的物件給另一個物件賦值時;
Hero hero;hero = hero1;
將hero1的成員的值一一拷貝給hero.
4.解構函式:
1.沒有返回值型別
2.函式名:類名(A ~Hero)
3.沒有形參
4.不支援過載
呼叫:記憶體被回收或者釋放時.
對於系統回收的記憶體:先構造的後析構.
對於手動申請的記憶體:根據delete先後順序.
5.類中資料成員為一個類的物件時;
6.沒有記憶體洩漏的情況下,建構函式和解構函式的個數相同.
7.malloc/free和calloc/free不會呼叫建構函式和解構函式.
8.類的物件的記憶體:
1.記憶體對齊
2.空類:1個位元組.
十二、類的封裝
1.A類中具有B類的子物件,
建構函式:B-A
解構函式:A-B
2.預設拷貝建構函式:淺拷貝(將一個物件的值
一一拷貝給另一個物件)
淺拷貝可能會造成兩個指標指向同一段記憶體.
當類的成員中含有指標並且指向堆區記憶體時,必須重寫拷貝建構函式,
實現深拷貝.

 1 Map::Map(const Map& other)
 2 {
 3     //m_row = other.m_row;
 4     //m_line = other.m_line;
 5     //pMap = other.pMap;
 6     getMemory(other.m_row, other.m_line);
 7     //將other.pMap指向記憶體中的值拷貝給this->pMap
 8     for (int i = 0; i < m_row;i++)
 9     {
10         memcpy(pMap[i], other.pMap[i], sizeof(int)*m_line);
11     }    
12 }

3.資料成員賦值:
1.訪問許可權為public:物件.成員 = 值;
2.在類外訪問私有成員,公有的成員方法:get/set函式
3.建構函式
4.成員初始化列表:(在分配記憶體時初始化)

1 Hero::Hero(int h, int l)
2     :hp(h), 
3      lv(l)
4 {
5     /*hp = 100;
6     lv = 2;*/
7     getLv();
8 }

4.成員函式:
資料成員和成員函式:
const:增加程式的穩定性.
const資料成員:1.必須使用成員初始化列表初始化
2.不能修改該成員的值
math:PI
const的成員函式:
返回值型別 函式名(形參表) const;
1.不能在函式內修改成員的值.
2.形參的值可以修改.
3.函式內不能呼叫非const的成員函式.

5.static資料成員:
1.必須在類外初始化
型別 類名::變數名 = 值;//如果沒有賦值,則預設為0
2.記憶體在全域性區,程式結束記憶體才回收,
記憶體不屬於類的一部分.
3.被類的所有物件共享,一個物件改變了其值,
其他物件訪問時也是改變後的值.
4.1.靜態成員可以通過類的物件呼叫
2.直接通過類名呼叫:A::a;

6.static成員函式:(在函式返回值前加上static)
函式內部只能訪問static資料成員或者呼叫static成員函式.
管理者:只有1個.
設計模式:23種(大話設計模式)
單例項模式:只能建立一個物件.(程式結束才回收記憶體)
1.建構函式私有化
2.在類中寫一個函式(靜態)用來建立物件
3.儲存第一次建立的例項的地址
(static成員函式只能訪問static成員)
1.在類外不能建立物件:建構函式私有化.
2.在堆區建立物件:解構函式私有化
7.友元:實現資料共享(可以訪問私有成員)
破壞了類的封裝性.
1.友元函式:(相當於全域性函式)
1.不屬於類的成員函式,沒有this指標.

2.宣告:類中
friend 返回值型別 函式名(形參表);
3.定義:類中和類外都可以
不需要加類的作用域符號.
4.呼叫:函式名(實參表);不需要通過物件呼叫

2.友元類:
1.friend 類名;
1.不可逆性:A是B的友元類,B不一定是A的友元類.
2.不可傳遞性:A是B的友元類,B是C的友元類,A不一定是C的友元類.
3.不可繼承性:A是B的友元類,C是A的子類,C不一定是B的友元類.

8.運算子過載:實現兩個自定義型別物件之間的運算.
1.類的成員函式:
返回值型別 operator運算子(形參表);
函式名:operator運算子
形參表個數:運算子左右的式子個數-1
2.友元函式:
形參個數為式子左右個數.
一切能寫成成員函式的過載都可以寫成友元,只是形參個數+1.
能寫成友元函式的過載不一定能寫成成員函式,
比如運算子的左邊的式子不為該類的物件.(必須使用友元)
cout<<hero;//運算子:<< 左邊:ostream 右邊;Hero
cout.operator<<(hero);
//hero<<cout;//hero.operator<<(cout);

9.指向類的資料成員
定義:成員的型別 類名::*指標名 = &類名::成員名;
在類外指標指向:只能指向公有成員
int Hero::*p = &Hero::hp;//p指標指向成員hp
Hero hero;
hero.hp = 100;
通過指標訪問成員

1 hero.*p = 200;
2             cout << hero.hp << endl;
3             Hero hero1;
4             hero1.*p = 300;
5             cout << hero.hp << endl;
6             cout << hero1.hp << endl;
7             Hero* pHero = new Hero;
8             pHero->hp = 500;
9             pHero->*p = 600;

10.成員函式指標
返回值型別(類名::*成員函式指標名)();
賦值:1.&類名::成員函式名
呼叫:(物件.*成員函式指標名)(實參表);
(指向物件的指標->*成員函式指標名)(實參表);
指標指向Hero的getHp成員函式
int(Hero::*pFunc)() = &Hero::getHp;
cout<<(hero.*pFunc)()<<endl;//等同於hero.getHp();
(pHero->*pFunc)();//pHero->getHp();

十三、類的繼承
1.繼承:除了具有父類的屬性和行為外,
還具有自己特定的屬性和行為.
父類:桌子 子類:圓桌/方桌等
父類:動物 子類:貓/狗等
父類:物體 子類:英雄/怪物等
子類也是父類中的一種.
父類派生子類/子類繼承父類.
定義:產生了新類.
class 類名:派生許可權 父類名1,派生許可權 父類名2…
{
訪問許可權:
//獨有的資料成員和成員函式
};
成員訪問許可權
派生許可權: public
protected
private

public
public
protected
不可訪問

protected
protected
Protected 不可訪問
private
private
private
不可訪問

建構函式:父類建構函式(按照繼承的順序從左往右)-子類建構函式
解構函式:子類解構函式-父類解構函式(按照繼承的順序從右往左)
呼叫父類的帶參建構函式:
成員初始化列表
(防止訪問非法記憶體):
父類與子類物件之間的賦值:
子類物件可以給父類物件賦值,
父類物件不可以給子類物件賦值.

子類指標可以給父類指標賦值.
父類指標不可以給子類物件賦值.
記憶體:記憶體對齊,為父類成員+子類成員的大小.
String類的四大函式

十四、類的多型:
1.單例項模式/外觀模式(Game)/簡單工廠模式
2.隱藏:當子類中出現與父類同名的成員(二義性),
父類成員被隱藏.
同名方法不同形參時,子類物件也不能呼叫父類方法.
3.基類指標指向子類物件時,如果成員方法前
沒有virtual關鍵字,則呼叫為基類函式.
4.指標呼叫成員或者非virtual成員函式時,
根據指標指向的型別.(靜態多型(編譯期多型))

多型:對同一訊息的不同響應.
5.動態多型(執行時多型):繼承+虛擬函式
(在函式宣告前加virtual關鍵字)
靜態多型:看指標型別
動態多型:看記憶體
6.具有虛擬函式的類的大小:+4個位元組(虛指標記憶體)
虛表:按順序存放了該類的所有虛擬函式的地址.
虛指標指向虛表.
虛擬函式:物件.虛擬函式(實參表);//通過虛指標找虛表中的虛擬函式
7.虛擬函式也可以被繼承,
1.如果沒有重寫(override)虛擬函式,則父類與子類物件
虛指標指向的虛表中的內容相同.
2.如果重寫:
1.virtual關鍵字可寫可不寫
2.函式形參表後override可寫可不寫,
寫了表示重寫父類的某函式
(如果父類沒有該函式則會報錯)

  1. 虛解構函式:基類指標指向子類物件,用基類指標釋放物件,
    如果基類不使用虛解構函式,不會釣魚派生類解構函式,
    需要在子類解構函式內釋放記憶體時.
    2.在子類中產生一個新的虛擬函式,
    不會產生新的虛指標.而是原先的虛指標
    指向虛表,虛表新增一個函式的地址.
    3.哪些函式不能定義為虛擬函式(虛指標+this)?
    1.建構函式(普通/帶參/拷貝):沒有為虛指標分配記憶體
    2.靜態函式:可以直接通過類名呼叫(也沒有虛指標記憶體)
    3.友元函式:不屬於類的成員,沒有this指標.
    4.普通非成員函式:不屬於類的成員.
    5.行內函數:在編譯階段展開,虛擬函式是執行時多型.
    6.純虛擬函式:virtual 返回值型別 函式名(形參表) = 0;

抽象類:只有宣告,沒有定義(函式體)具有一個或以上純虛擬函式的類稱為抽象類.
Animal:
Object:
1.不能建立物件,可以建立指標或者引用.
2.抽象類的子類必須實現純虛方法,才能
建立物件.
8.轉換:
1.強轉(不安全性)
2.四種安全型別轉換
轉換型別關鍵字<轉換型別>(轉換內容);
const_cast:
1.消除或者新增const屬性
2.指標或者引用操作
static_cast:靜態轉換
1.普通型別之間的轉換
2.指標間的轉換(父子級關係,考慮偏移)
reinterpret_cast:重新解釋轉換
1.void到任意指標之間的轉換
2.任意指標到void
的轉換
3.任意指標到任意指標之間的轉換
dynamic_cast:動態轉換
1.繼承+虛擬函式