C++.png
內(nèi)聯(lián)函數(shù) inline function
- 使用inline修飾函數(shù)的聲明或者實(shí)現(xiàn),可以使其變成內(nèi)聯(lián)函數(shù)。
- 一般建議聲明和實(shí)現(xiàn)都增加inline修飾,被inline修飾的函數(shù)
特點(diǎn):
- 編譯器會(huì)將函數(shù)調(diào)用直接展開為函數(shù)體代碼,好處是可以減少函數(shù)調(diào)用的開銷,但是會(huì)增大代碼體積。
- 一般在頻繁調(diào)用而且代碼體積不大(不超過10行)的時(shí)候用。即使被inline修飾,但是函數(shù)體積過大,不會(huì)被編譯器內(nèi)聯(lián),比如遞歸函數(shù)
內(nèi)聯(lián)函數(shù)與宏
- 內(nèi)聯(lián)函數(shù)和宏,都可以減少函數(shù)調(diào)用的開銷
- 對(duì)比宏,內(nèi)聯(lián)函數(shù)多了語法檢測(cè)和函數(shù)特性
// 思考以下代碼的區(qū)別
#define sum(x) (x + x)
inline int sum(int x) { return x + x; }
// 使用:
int a = 10; sum(a++);
#pragma once
- 我們經(jīng)常使用#ifndef、#define、#endif來防止頭文件的內(nèi)容被重復(fù)包含
-
pragma once可以防止整個(gè)文件的內(nèi)容被重復(fù)包含
- 區(qū)別:
-
ifndef、#define、#endif受C\C++標(biāo)準(zhǔn)的支持,不受編譯器的任何限制
- 有些編譯器不支持#pragma once(較老編譯器不支持,如GCC 3.4版本之前),兼容性不夠好
-
ifndef、#define、#endif可以針對(duì)一個(gè)文件中的部分代碼,而#pragma once只能針對(duì)整個(gè)文件
-
引用(Reference)
- 在C語言中,使用指針(Pointer)可以間接獲取、修改某個(gè)變量的值
- 在C++中,使用引用(Reference)可以起到跟指針類似的功能
- 引用存在的
價(jià)值之一
:比指針更安全
、函數(shù)返回值可以被賦值
int main() {
// 定義了一個(gè)引用,相當(dāng)于是變量的別名
// rAge就是一個(gè)引用
int age = 2;
int &rAge = age;
int &rAge1 = rAge;
int &rAge2 = rAge1;
rAge = 11;
cout << age << endl;
rAge1 = 22;
cout << age << endl;
rAge2 = 33;
cout << age << endl;
return 0;
}
// 對(duì)別名的理解
int age = 10;
const int &rAge = age;
age = 30;
cout << "age is " << age << endl;
cout << "rAge is " << rAge << endl;
// log:
age is 30
rAge is 30
注意:引用的類型要跟引用對(duì)象一致,否則引用不會(huì)指向?qū)ο蟮牡刂罚莿?chuàng)建一個(gè)新的地址,如下:
int age = 10;
const long &rAge = age;
age = 30;
cout << "age is " << age << endl;
cout << "rAge is " << rAge << endl;
// log:
age is 30
rAge is 10
// 數(shù)組的引用
int array[] = { 10, 20, 30 };
int (&rArray)[3] = array;
int *a[4];
int (*b)[4];
// int (&rArray)[4] = array;會(huì)報(bào)錯(cuò):
// Non-const lvalue reference to type 'int [4]' cannot bind to a value of unrelated type 'int [3]'
void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
void swap(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int v1 = 10;
int v2 = 20;
swap(v1, v2);
cout << "v1 is " << v1 << endl;
cout << "v2 is " << v2 << endl;
}
// log:
v1 is 20
v2 is 10
注意點(diǎn):
- 引用相當(dāng)于是變量的別名(基本數(shù)據(jù)類型、枚舉、結(jié)構(gòu)體、類、指針、數(shù)組等,都可以有引用)
- 對(duì)引用做計(jì)算,就是對(duì)引用所指向的變量做計(jì)算
- 在定義的時(shí)候就必須初始化,一旦指向了某個(gè)變量,就不可以再改變,“從一而終”
- 可以利用引用初始化另一個(gè)引用,相當(dāng)于某個(gè)變量的多個(gè)別名
- 不存在【引用的引用、指向引用的指針、引用數(shù)組】
const
- const修飾的對(duì)變量,不可修改,永遠(yuǎn)是這個(gè)值
- 如果修飾的是類、結(jié)構(gòu)體(的指針),其成員也不可以更改
// 以下5個(gè)指針的含義:
int age = 10;
const int * p0 = &age;
int const * p1 = &age;
int * const p2 = &age;
int const * const p3 = &age;
const int * const p4 = &age;
- 上面的指針問題可以用以下結(jié)論來解決:
- const修飾的是其右邊的內(nèi)容
- 因此:
- p0和p1是一樣的效果,不可修改【value】,可以修改指向
- p3和p4是一個(gè)的效果,都是不可修改【value】和指向
- p2可以修改【value】,不可修改指向
常引用(Const Reference)
- 引用可以被const修飾,這樣就無法通過引用修改數(shù)據(jù)了,可以稱為常引用
- const必須寫在&符號(hào)的左邊,才能算是常引用
const引用的特點(diǎn):
- 可以指向臨時(shí)數(shù)據(jù)(常量、表達(dá)式、函數(shù)返回值等)
- 可以指向不同類型的數(shù)據(jù)
- 作為函數(shù)參數(shù)時(shí)(此規(guī)則也適用于const指針)
- 可以接受const和非const實(shí)參(非const引用,只能接受非const實(shí)參)
- 可以跟非const引用構(gòu)成重載
- 當(dāng)常引用指向了不同類型的數(shù)據(jù)時(shí),會(huì)產(chǎn)生臨時(shí)變量,即引用指向的并不是初始化時(shí)的那個(gè)變量
數(shù)組的引用
- 常見的2種寫法
int arr[3] = {1, 2, 3};
int (&ref1)[3] = arr;
int const *ref2 = arr;
cout << arr << endl;
cout << ref1 << endl;
cout << ref2 << endl;
// log:
0x7ffeefbff4cc
0x7ffeefbff4cc
0x7ffeefbff4cc
引用的本質(zhì)
- 引用的本質(zhì)就是指針,只是編譯器削弱了它的功能,所以引用就是弱化了的指針
- 一個(gè)引用占用一個(gè)指針的大小
void test(){
int age = 10;
int *p1 = &age;
int &ref = age;
cout << *p1 << endl;
cout << ref << endl;
cout << p1 << endl;
cout << &ref << endl;
}
// 函數(shù)調(diào)用棧:
0x1000011e0 <+0>: pushq %rbp
0x1000011e1 <+1>: movq %rsp, %rbp
0x1000011e4 <+4>: subq $0x40, %rsp
0x1000011e8 <+8>: movq 0xe19(%rip), %rdi ; (void *)0x00007fffa56a4770: std::__1::cout
-> 0x1000011ef <+15>: movl $0xa, -0x4(%rbp)
0x1000011f6 <+22>: leaq -0x4(%rbp), %rax
0x1000011fa <+26>: movq %rax, -0x10(%rbp)
0x1000011fe <+30>: movq %rax, -0x18(%rbp)
0x100001202 <+34>: movq -0x10(%rbp), %rax
0x100001206 <+38>: movl (%rax), %esi
...
...
// log:
10
10
0x7ffeefbff4bc
0x7ffeefbff4bc
- 可以看到,<+26>和<+30>都是本質(zhì)都是一樣的:把變量age的地址值賦值給指針/引用