C++知識點總結(基礎語法2-內聯函數, const, 引用)

內聯函數1(inline function)

(1)使用inline修飾函數的聲明或實現, 可以使其變成內聯函數.
(2)建議聲明和實現都增加inline修飾
特點:
(1)編譯器會將函數調用直接展開爲函數體代碼, 就不存在函數調用了.
代價:會增加代碼數量, 使代碼變臃腫.
但是如果不使用內聯函數的話, 由於在函數調用過程中, 會先開闢棧空間給函數, 然後執行函數內的代碼, 最後回收棧空間.存在這樣一個操作, 如果這個函數頻繁調用的話, 就會頻繁進行這個操作, 使效率變低.
所以什麼時候使用內聯函數?
1.函數代碼體積不大
2.頻繁調用函數

(2)可以減少函數調用的開銷
(3)會增大代碼體積
注意:
(1)儘量不要內聯超過10行代碼的函數
(2)有些函數即使聲明爲inline, 也不一定會被編譯器內聯, 比如遞歸函數(無法內聯).

內聯函數與宏

(1) 內聯函數和宏, 都可以減少函數調用的開銷.
(2)對比宏, 內聯函數多了語法檢測和函數特性.

const

(1)const修飾的變量必須在定義時就指明它的值.
(2)如果修飾的是類或結構體(的指針), 其成員也不可以更改.
注意: 在C語言中定義結構體變量struct Date d = {2019,1,2};
但在C++裏定義結構體變量時, 不需要struct, 可以直接Date d = {2010,2,2};
(3)在這裏插入圖片描述

引用(Reference)

(1)在C語言中, 使用指針(Pointer)可以間接獲取, 修改某個變量的值
(2)在C++中, 使用引用(Reference)可以起到跟指針類似的功能.

#include <iostream>
using namespace std;

int main()
{
    int age = 10;

    // 定義了一個age的引用, refAge相當於是age 的別名
    int &refAge = age;
    refAge = 20;
    
    cout << age << endl;
    // 結果是20
    return 0;
}

注意點:
(1)引用相當於是變量的別名(基本數據類型, 枚舉, 結構體, 類, 指針, 數組等, 都可以有引用)
(2)對引用做計算, 就是對引用所指向的變量做計算.
(3)在定義的時候就必須初始化, 一旦指向了某個變量, 就不可以再改變, "從一而終"
(4)可以利用引用初始化另一個引用, 相當於某 個變量的多個別名.
(5)
(6)默認情況下引用類型要跟引用的變量類型匹配
引用存在的價值之一:比指針更安全, 函數返回值可以被賦值.

引用的本質

(1)引用的本質就是指針, 只是編譯器削弱了它的功能, 所以引用就是弱化了的指針.
x86: 32位 指針4個字節
x64: 64位 指針8個字節
(2)一個引用佔用一個指針的大小

彙編語言

學習彙編語言2大知識點:
1.彙編指令
2.寄存器
C++可以輕易反彙編, 可以馬上知道所寫的C++代碼的本質是什麼.而其他的語言不容易看到.
彙編語言種類:
(1)8086彙編(16bit)
(2)x86彙編(32bit)
(3)x64彙編(64bit), 目前都是
(4)ARM彙編(嵌入式, 移動設備)
x64彙編根據編譯器的不同, 有2種書寫格式
(1)intel VS
(2)AT&T GCC, MAC
彙編語言不區分大小寫
mov eax, 10
MOV EAX, 10
等價
在這裏插入圖片描述

x64彙編-寄存器(Registers)

不同的架構, 寄存器不一樣
RAX\RBX\RCX\RDX : 通用寄存器
x86 32位一個寄存器能存4個字節
x64 一個寄存器能存8個字節
x64彙編兼容以前的彙編,(兼容以前的寄存器).
所以在RAX的低四個字節是EAX寄存器, EAX的低2個字節是AX寄存器, AX又分爲AH和AL
AH H high AX的高位
AL L low AX的低位
在這裏插入圖片描述
在這裏插入圖片描述
**結論:**所以如果給RAX賦8個字節的值(例如:1122334455667788), 會把原來賦值給EAX的值覆蓋成55667788, 並把AX原來的值覆蓋成7788.
x86 環境下(32位)
EAX\EBX\ECX\EDX : 通用寄存器
8086(16位)
AX\BX\CX\DX\ : 通用寄存器
一般的規律:
R開頭的寄存器是64bit的, 佔8個字節
E開頭的寄存器是32bit的, 佔4個字節

mov指令

(1)mov dest, src
將src的內容賦值給dest, 類似與dest = src
(2)[地址值]
中括號[]裏面放的都是內存地址
word 是 2 字節, dword 是 4 字節(double word), qword是8字節(quad word)
int a = 4;
對應彙編:mov dword ptr [ebp-xxh] 4
ptr是固定寫法, ebp-xxh是a的地址,dword說明是4個字節, 所以會把ebp-xxh往高地址的包括ebp-xxh的4個內存地址賦值成4
在這裏插入圖片描述
(3)call 函數地址
一旦看到call 一定是調用函數
call之前的push都是傳參
(4)變量地址總結
一個變量的地址值, 是它所有字節地址中的最小值.
例: int a = 4;
a有4個字節, 那每一個字節都有一個內存地址.
所以它所有字節地址中的最小值就是變量a 的地址值.
&a 的值是0x007DF968
大小端模式, 現在大部分都是小端模式.
小端模式:
4的二進制00000000 00000000 00000000 00000011
存儲時:高字節對應高地址,低字節對應低地址
所以內存地址 內容
0x7DF968 00000011
0x7DF969 00000000
0x7DF96A 00000000
0x7DF96B 00000000
讀取時:從高地址讀取所以讀取00000000 00000000 00000000 00000011
(5)lea dest, [地址值]
lea : load effect address 裝載一個有效的地址值
lea eax, [1122H]
意思:直接將地址值賦值給eax
如果是mov eax, [1122H]
意思是:取出1122H這個地址存放的值再賦值給eax.
(6)ret
ret: return
函數返回
(7)xor op1, op2
將op1和op2異或的結果賦值給op1, 類似與op1 = op1 ^ op2
(8)add op1, op2
類似於op1 = op1 + op2
(9)sub op1, op2
類似於op1 = op1 - op2
(10)inc op
inc : increase
自增, 類似於 op = op + 1
(11)dec op
dec : decrease
自減, 類似於op = op - 1
(12)jmp 內存地址
jmp : jump 跳轉
調轉到這個內存地址對應的代碼
j開頭的一般都是跳轉, 大多數是帶條件的跳轉, 一般跟test, cmp等指令配合使用.
(13)jne :jump not equal, 比較結果不相等才跳轉.
其他j開頭的彙編指令詳見jcc(Jump Condition Code)文件

const 引用(常引用Const Reference)

引用可以被const修飾, 這樣就無法通過引用修改數據了, 可以稱爲常引用.
(1)const int &ref = age;
ref = 30; // 錯誤
可以訪問
類似於 const int *ref = &age;
(2)int & const ref = age;
ref = 30; // 正確
意思是ref不能修改指向, 但是可以通過ref間接修改所指向的變量
但沒有意義, 因爲ref本來就不能修改指向.
所以const 必須寫在&的左邊, 才能算是常引用.

const引用的特點

(1)可以指向臨時數據(常量, 表達式, 函數返回值等)
(2)可以指向不同類型的數據.
(3)作爲函數參數時(此規則也適用於const指針)
1.可以接受const和非const實參(非const引用, 只能接受非const實參)

#include <iostream>
using namespace std;

int sum(const int &v1,const int &v2) {
    return v1 + v2;
}

int main()
{
    // 非const實參
    int a = 10;
    int b = 20;
    sum(a, b);
    
    // const實參
    const int c = 10;
    const int d = 20;
    sum(c, d);

    sum(10, 20);
    return 0;
}

因爲如果非const引用可以接受const實參的話, 在函數裏面可以v1 = 20; 這樣就會改變c的值, 但c是const的常量, 所以會衝突矛盾.
2.可以跟非const引用構成重載.

int sum(int &v1, int &v2) {

}
int sum(const int &v1, const int &v2) {
	
}

如果不是引用時,就不能構成重載.

int sum(int v1, int v2) {

}
int sum(const int v1, const int v2) {
	
}
// 不行

補充:當常引用指向了不同類型的數據時, 會產生臨時變量, 即引用指向的並不是初始化時的那個變量.

數組的引用.

(1)
int arr[] = {1,2,3};
int (&ref)[3] = arr;
ref[1] = 10;
類似於0
int arr[] = {1,2,3};
int (*p)[3] = arr;
p[1] = 10;
(2)
int arr[] = {1,2,3};
int * const &ref = arr;
因爲數組名arr其實是數組的地址, 也是數組首元素的地址
數組名arr可以看做是指向數組首元素的指針.(int *類型), 又因爲數組的地址不能修改是常量
所以可以寫成, int * const &ref = arr; 常引用


其他C++系列文章:

C++知識點總結(基礎語法1-函數重載, 默認參數)
C++知識點總結(基礎語法2-內聯函數, const, 引用)
C++知識點總結(面向對象1-類和對象, this指針, 內存佈局)
C++知識點總結(面向對象2-構造函數, 初始化列表)

C++知識點總結(面向對象3-多態)

C++知識點總結(面向對象4-多繼承, 靜態成員static)
C++知識點總結(面向對象5-const成員, 拷貝構造函數)
C++知識點總結(面向對象6-隱式構造, 友元, 內部類, 局部類)
C++知識點總結(其他語法1-運算符重載)
C++知識點總結(其他語法2-模板, 類型轉換, C++11新特性)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章