緒論
? ? ? ? 從本章開始我們正式進(jìn)入到C++的內(nèi)容,對此如果沒有學(xué)習(xí)過C語言的建議先將C語言系統(tǒng)的學(xué)習(xí)一遍后再來(已經(jīng)更新完在專欄就能看到)。
話不多說安全帶系好,發(fā)車?yán)?strong>(建議電腦觀看)。
附:紅色,部分為重點部分;藍(lán)顏色為需要記憶的部分(不是死記硬背哈,多敲);黑色加粗或者其余顏色為次重點;黑色為描述需要
思維導(dǎo)圖:
要XMind思維導(dǎo)圖的話可以私信哈
目錄
1.C++關(guān)鍵字
2.命名空間(namespace)
2.1命名空間
2.1.1 域:
2.1.2命名空間域的展開:
3.C++的輸入和輸出
4.缺省參數(shù)(默認(rèn)參數(shù))
5.函數(shù)重載
6.引用
6.1引用的定義:
6.2使用場景:
6.3常引用問題
6.4引用的總結(jié):
7.關(guān)鍵字auto
8.范圍for
9.內(nèi)聯(lián)函數(shù)
?10.指針空值nullptr
1.C++關(guān)鍵字
知識點:
C++的關(guān)鍵字的含義和C語言中一樣都是有特殊意義的名稱,我們在創(chuàng)建變量的時候不能使用相同的名。
細(xì)節(jié):
下面是C++中的63個關(guān)鍵字,我們不需要去死記,通過不斷學(xué)習(xí)自然就記住了。
2.命名空間(namespace)
2.1命名空間
在C語言中會有命名沖突的問題,在c++中為了避免一個項目中不同程序員寫的代碼(或者程序員寫的變量名和庫函數(shù)的函數(shù)名)發(fā)生命名的沖突,就推出了命名空間這個概念來解決命名沖突這個問題。對此命名空間內(nèi)可以定義變量、函數(shù)、結(jié)構(gòu)體、再嵌套一個命名空間??......
知識點:
2.1.1 域:
域一般分為:全局域、局部域、作用域(C語言已講)、命名空間域、類域
細(xì)節(jié):
下面通過代碼來展示不同的域:
namespace ZYK { int a = -1;//在命名空間的變量,就是命名空間域 } int a = 1;//全局域 int main() { int a = 0;//在局部變量中就是局部域,和局部變量非常類型 return 0; }
- 對于域的使用優(yōu)先級一般是:局部域 , 全局域?
- 若加上了 域作用限定符 : “ :: ” 的話則會更先執(zhí)行限定符指定的空間,域作用限定符的使用是:左邊是命名空間名 ::右邊則是要執(zhí)行的變量名
- 當(dāng)沒有指定/展開命名空間域時在搜索變量時并不會自動去命名空間域內(nèi)去搜索,命名空間域時DIY名稱的。
- ?對于全局域來說他的域名就是空(即當(dāng)不輸入域名時就代表要訪問全局域)
2.1.2命名空間域的展開:
知識點:
他的意思和他的名字一樣:
就是把一個命名空間進(jìn)行了展開,直接展開到了全局域中,所以要注意的是如果全局域有和命名空間域相同的變量名時就會報錯(命名不明確),對此我們反思到,在一般情況下我們加上這個命名空間就是為了防止這種情況,所以我們一般看情況展開(在一多人合作的項目中我們不能進(jìn)行展開、而在日常自己練習(xí)和單獨完成的項目我們可以適當(dāng)?shù)倪M(jìn)行展開)
基本語法:
using + namesapce + 命名空間名來展開對應(yīng)的命名空間
附:當(dāng)同時定義了多個相同名的命名空間時,此時會將這幾個相同的命名空間進(jìn)行合并,同樣也不能有相同的變量名
????????????????????????????????????????????????下面通過練習(xí)來實踐:
練習(xí):
1. 在有局部域和全局域以及命名空間域的同時,先執(zhí)行全局域再執(zhí)行命名空間域最后訪問局部域:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
namespace ZYK
{
int a = -1;//在命名空間的變量,就是命名空間域
}
int a = 1;
int main()
{
int a = 0;
printf("%d\n", ::a);
printf("%d\n", ZYK::a);
printf("%d\n", a);
return 0;
}
2. 對于嵌套的來說其大體使用方法一樣(嵌套的指定即可):
這里就不過多的去敘述了,直接通過代碼來展示:
3. 展開命名空間:
namespace ZYK
{
int a = -1;
}
using namespace ZYK;
int main()
{
int a = 0;
printf("%d\n", ::a);
printf("%d\n", ZYK::a);
printf("%d\n", a);
return 0;
}
3.C++的輸入和輸出
知識點:
std是C++的標(biāo)準(zhǔn)庫的命名空間的域名,C++的標(biāo)準(zhǔn)庫的定義和實現(xiàn)都放在了這個命名空間內(nèi)(和C語言中的 stdio.h 這個頭文件有點類似 在std中包含的則是C++標(biāo)準(zhǔn)庫的函數(shù))
細(xì)節(jié):
上面我們知道了c++中有一個命名空間名std ,他其中包含了許多函數(shù),所以為了使用一個命名空間內(nèi)的函數(shù)。我們就有兩種方法也就是域作用限定符來指定/展開命名空間域
但是要注意的是并不是展開/指定了就能使用該函數(shù)了,同樣要先用#define包含頭文件,再通過std來間接的訪問函數(shù)。所以說這兩樣?xùn)|西缺一不可。
練習(xí):
1. cout、endl
一般來說cout 和 endl 是同時使用的,
cout:(可以大概的理解成我們程序的那個黑框框)可以將 <<? (流插入運(yùn)算符) 流進(jìn)來的進(jìn)行打印
endl:其實可以大概的看成? \n?
cout 相較于printf來說:他可以連續(xù)一行插入多個數(shù)據(jù),并且可以自動識別類型
附:而cin流提取運(yùn)算符(類似scanf)
練習(xí)使用方法如下:
第一種方法:
一個正常使用該cout、endl時我們需要加上的條件:
頭文件:#include<iostream>? 、 展開std命名空間
優(yōu)點:可以能更加便捷的使用
缺點:同樣直接把一個命名空間打開是一個非常危險的舉動
第二種方法:
?此時我們并沒有去展開一個命名空間,通過指定訪問的方法來實現(xiàn)
但是:不要忘記了頭文件#include<iostream>
優(yōu)點:沒有了展開命名空間的風(fēng)險
缺點:若要多次使用則會些冗雜
第三種方法(也是比較推薦的方法):
這種方法是將所要用到的進(jìn)行單獨的展開,我們可以在常用的對應(yīng)進(jìn)行展開,而不常用的直接使用第二種方法
頭文件?#include<iostream>(不能省略)
附:cout的自動識別的展示、以及因為自動識別而導(dǎo)致的精度丟失的問題(缺點)
附:在c++中可以寫c的語法,因c++是兼容c的(所以我們printf和cout混著使用)
4.缺省參數(shù)(默認(rèn)參數(shù))
知識點:
在函數(shù)的形參部分加上一個初始值(缺省參數(shù)),當(dāng)你沒傳參數(shù)時就會用缺省參數(shù),如果你傳了參數(shù)那就正常的使用傳來進(jìn)的參數(shù)值。
細(xì)節(jié):
當(dāng)我們同時有多個形參時,對于缺省參數(shù)的使用情況大概和單個時的情況差不多但是要注意的是:
- 傳參時是從左往右依次傳上去的(所以從左往右的算傳幾個算幾個,若沒傳就用缺省參數(shù))
- 并且不可以跳躍的來傳遞實參
- 缺省參數(shù)必須是從右往左的確立的(即若一半是正常形參一半是缺省形參時,此時正常形參必須在缺省形參的左邊,這種形參別稱為半缺省型,反之全缺省)
當(dāng)我們分源管理時我們應(yīng)該在哪里寫這個缺省參數(shù)呢:
缺省參數(shù)應(yīng)該只寫在函數(shù)的聲明處(因為怕出現(xiàn)聲明和定義不同的問題),而不是寫在定義處
練習(xí):
1. 缺省參數(shù)的具體應(yīng)用:
2. 傳多個參數(shù)時要注意的點
a.不能跳躍傳參
b.從左往右傳參的
c.半缺?。海ㄈ笔?shù)必須從右往左,因為我們傳參是從左往右的)
5.函數(shù)重載
知識點:
在C語言中我們無法同時使用多個相同函數(shù)名但類型不同的函數(shù),所以c++就對這方面進(jìn)行了優(yōu)化,讓同名當(dāng)不同參數(shù)類型的函數(shù)可以正常使用
細(xì)節(jié):
對于函數(shù)重載時的參數(shù)一般分為三類:
- 類型不同
![]()
- 類型的數(shù)量不同
![]()
- 類型的順序不同
![]()
- 總結(jié)來說就是:兩個同名的函數(shù)其函數(shù)類型不能對應(yīng)相等即可?
![]()
而對于為什么C語言不能對相同的函數(shù)名的函數(shù)進(jìn)行函數(shù)調(diào)用而c++卻可以:
是因為在編譯鏈接階段 創(chuàng)建的符號表中命名的函數(shù)命有區(qū)別 ,C語言是直接把函數(shù)名命名當(dāng)成符號表,而c++在生成符號表時的命名規(guī)則并不是直接用函數(shù)名而是有不同的命名規(guī)則
因此對于C語言來說當(dāng)出現(xiàn)兩個相同函數(shù)名時,就會導(dǎo)致鏈接時沖突、
而對于c++來說就不會出現(xiàn)沖突因為類型的不同所以函數(shù)命名就會不同(在gcc環(huán)境下的函數(shù)名的命名規(guī)則是:_Z3funii? ?其中_Z是固定的 + 3 是函數(shù)名的字符個數(shù)?+ 函數(shù)名 + 函數(shù)的類型 ii : 兩個整形)
6.引用
知識點:
6.1引用的定義:
引用不是新定義一個變量,而是給已存在變量取了一個別名,在語法層面上編譯器不會為引用變量開辟內(nèi)存空間,它和它引用的變量共用同一塊內(nèi)存空間。(就像綽號,叫真名和綽號是一樣的)
引用的基本語法:引用的對象的類型+&+引用名 =引用的對象?
//整形
? ? int a = 0;
? ? int& b = a;//指針
? ? int * ptr = NULL;
? ? int*& rp = ptr;
?細(xì)節(jié)(注意點):
- 在創(chuàng)建引用定義時必須初始化:int& b = a;
![]()
- 一個變量可以用多個引用(一個人在每個階段都可能有不同的綽號,但都是指同一個人)
int main() { int a = 0; int& b = a; int& c = a; // b 、 c 都是a的引用 }
- 只能一開始進(jìn)行引用的初始化指定引用對象、后面無法進(jìn)行修改。(后面修改也只是賦值操作)
6.2使用場景:
- 引用做參數(shù)
- 輸出型參數(shù) ,像我們之前在C語言寫鏈表來舉例,當(dāng)需要改變phead時就需要傳一個二級指針,但此時我們用到了引用就不用再使用二級指針。
![]()
- 提高效率,因為引用的物理意義是一個變量的別名,在傳參時并不用為其開辟棧幀所以可以提高一定的效率。
- 引用做返回值
- 但要小心,引用返回的對象不能在棧里面,否則當(dāng)出棧幀時就會導(dǎo)致非法訪問,一般用于靜態(tài)區(qū),堆區(qū)上的
- 可以修改返回值
- 提高效率,當(dāng)引用做返回值的時候,返回的就是一個變量的別名,此時在傳遞回去的過程中就不需要創(chuàng)建臨時變量(放到寄存器)的返回,這樣就能減少損耗
練習(xí):
1. 通過引用來進(jìn)行數(shù)值的交換(在C語言中我們需要用到指針才能完成)
//指針時:void Swap(int * a, int * b)
void Swap(int& a, int& b)//此時的a 、 b 是參數(shù)的引用
{
int tmp = a;
a = b;
b = tmp;
}
int main()
{
int a = 10;
int b = 20;
cout << a << ' ' << b << endl;
Swap(a,b);
cout << a << ' ' << b << endl;
return 0;
}
6.3常引用問題
知識點:
對常數(shù)的引用時要注意的點(此處主要討論的是const修飾的常變量)
- 在引用時,引用的類型相對于引用對象的類型來說只能平移或者降低(注意看注釋,若看不懂后面有一個附加知識點)
![]()
- 一種特殊情況:
![]()
附:當(dāng)需要整形提升/截斷時他們在賦值前都會先創(chuàng)建一個臨時變量,把這個提升、截斷后的值先放到這個臨時變量(寄存器)內(nèi),再把這個臨時變量的值放到所要賦值的空間中(這樣就避免把被賦值的值改變)
就是因為一個臨時變量具有常性,所以需要加上const來修飾
臨時變量具有常性? ,同理對于函數(shù)返回時也是一樣的,當(dāng)我們返回一個臨時變量時是有常性的所以需要用到常變量const來修飾
?此時我們還需要注意的點是:當(dāng)返回值是引用時就不會創(chuàng)建臨時變量了。
6.4引用的總結(jié):
知識點:
- 在語法層面上我們理解的是引用并不開辟空間,但是在底層來說其原理和指針一樣也是需要開辟空間的(我們理解了解底層即可平時就記住語法層面 : 就像老婆餅里沒老婆)
底層邏輯一樣
- 指針和引用的區(qū)別
- 沒有NULL引用這種概念,而指針有空指針的概念
- sizeof中指針和引用有不同,引用的結(jié)果就是引用對象類型的大小,而指針時地址的大小
- 引用和指針的加減不一樣
- 有多級指針,沒有多級引用
- 指針需要解引用,而引用操作系統(tǒng)自動處理了
- 引用比指針更加安全(指針可能會有野指針的問題)
7.關(guān)鍵字auto
知識點:
一種可以根據(jù)左邊表達(dá)式自動推到出其類型然后定義給變量
具體就用實例來描述:
int main() { int x = 10; auto a = &x;//因為地址,所以auto是指針類型 auto* b = &x; auto& c = x; cout << typeid(a).name() << endl;//int * cout << typeid(b).name() << endl;//int * cout << typeid(c).name() << endl;//int (引用的類型不用加上&) *a = 20; *b = 30; c = 40; return 0; }
此處的 auto 和 auto * 其實是一樣的
附:typeid(變量名). name()? ? 這個可以識別輸入變量的類型
細(xì)節(jié)(注意點):
- auto的價值是:一般適用于對一些比較長的類型進(jìn)行auto自動識別化
- 使用auto定義變量必須有初始化(在編譯階段編譯器根據(jù)初始化表達(dá)式推倒出表示的類型,其實auto并不是一個類型,在編譯后會將其改成實際的類型如#define定義宏類似)
![]()
- auto也可以一次性聲明多個變量,但是這幾個變量類型必須是相同的(因編譯器只對一個類型進(jìn)行推導(dǎo))
![]()
- auto不能用在形參部分來識別類型(編譯器無法對參數(shù)的實際類型進(jìn)行推導(dǎo))(c++14往后的可以作返回值)
![]()
- auto不能直接對數(shù)組進(jìn)行聲明
![]()
8.范圍for
知識點:
對數(shù)組進(jìn)行遍歷
語法: for (數(shù)組類型? 變量名? : 數(shù)組名)
細(xì)節(jié)(注意點):
當(dāng)把一個數(shù)組傳進(jìn)函數(shù)時其本質(zhì)是一個指針(數(shù)組名首元素地址)所以在該函數(shù)內(nèi)是不能去使用這個范圍for的
通過練習(xí)描述:
int main()
{
int a[] = { 1,2,3,3,4,5,6,7,8,9,10 };
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
cout << a[i] << ' ';
}
cout << endl;
for (auto x : a)// for (數(shù)組類型? 語法for的變量名? : 數(shù)組名)
{
cout << x << ' ';
}
cout << endl;
}
此時只是依次將數(shù)組a中的數(shù)據(jù)拷貝給x(所以拷貝的無法改變其數(shù)組內(nèi)容)
若想改變在數(shù)組a的值就需要加上引用 如下:
9.內(nèi)聯(lián)函數(shù)
知識點:
內(nèi)聯(lián)函數(shù)的設(shè)立是為了減少一些重復(fù)創(chuàng)建棧幀的開銷,以inline修飾的函數(shù)被叫做內(nèi)聯(lián)函數(shù),該函數(shù)不會去開辟棧幀,會直接在調(diào)用內(nèi)聯(lián)函數(shù)的地方展開使用。(在C語言中這種簡單重復(fù)使用的函數(shù)一般會用宏來實現(xiàn),但宏也有其自己的缺點所以c++進(jìn)行優(yōu)化創(chuàng)造出來內(nèi)聯(lián)函數(shù))
細(xì)節(jié):
- 內(nèi)聯(lián)函數(shù)的具體展現(xiàn):
?當(dāng)沒有使用內(nèi)聯(lián)函數(shù)時:就會正常的去調(diào)用函數(shù),開辟棧幀...
?當(dāng)使用內(nèi)聯(lián)函數(shù)后:調(diào)用內(nèi)聯(lián)函數(shù)的地方會直接展開使用(此時就沒用call調(diào)用函數(shù))。
- 內(nèi)聯(lián)函數(shù)對于編譯器來說是一個建議性的操作,最后是否實現(xiàn)取決于編譯器(對于編譯器來說:如果是遞歸函數(shù)/比較長函數(shù)他們就不會同意變成內(nèi)聯(lián)函數(shù))
- 注意對于一個較大的函數(shù)來說,不能使用內(nèi)聯(lián)函數(shù),因為內(nèi)聯(lián)函數(shù)會導(dǎo)致程序的指令變多(直接正常調(diào)用此時指令就在函數(shù)內(nèi)并不會變多,而內(nèi)聯(lián)函數(shù)會將函數(shù)展開就會導(dǎo)致指令反而變多,如:假如一個函數(shù)的指令是50個,然后又100處地方要調(diào)用這個函數(shù),此時對于直接調(diào)用函數(shù)的指令就是100 + 50 ,假如是內(nèi)聯(lián)函數(shù)就變成了 100 * 50)
- 假如你要分源管理,此時內(nèi)聯(lián)函數(shù)不要聲明和定義分離(因為內(nèi)聯(lián)函數(shù)不需要要調(diào)用就不會生成地址而這樣就不會進(jìn)入到符號表,若聲明和定義分開就會導(dǎo)致鏈接錯誤找不到,直接就寫定義即可)
?10.指針空值nullptr
????????在c++中NULL并不表示空指針而是表示為0(NULL實際是一個宏代表0),所以在c++11中就新引入了一個關(guān)鍵字表空指針nullptr????????
??
本章完。預(yù)知后事如何,暫聽下回分解。文章來源:http://www.zghlxwxcb.cn/news/detail-423595.html
持續(xù)更新大量C++細(xì)致內(nèi)容,三連關(guān)注哈文章來源地址http://www.zghlxwxcb.cn/news/detail-423595.html
到了這里,關(guān)于C++ 命名空間、域、缺省參數(shù)、函數(shù)重載、引用、auto、內(nèi)聯(lián)函數(shù)的知識點+完整思維導(dǎo)圖+基本練習(xí)題+深入細(xì)節(jié)+通俗易懂建議收藏的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!