C++入門(命名空間,缺省參數(shù),函數(shù)重載,引用,內(nèi)聯(lián)函數(shù),auto,范圍for)
一.C++關(guān)鍵字
C++總共有63個關(guān)鍵字,在入門階段我們只是大致了解一下就可,在后續(xù)博客中會逐漸講解
二.命名空間
相信學(xué)過C++的同學(xué),一定都寫過下面這個簡單的程序
#include<iostream> using namespace std; int main() { cout<<"hello world"<<endl; return 0; }
我們先來看第二行代碼,using namespace std , 這行代碼是什么意思呢 ?
這里我們就要來引入命名空間的概念,命名空間是用來解決C語言命名沖突問題的,在我們的C語言階段,如果我們寫了下面的程序,是不能通過編譯的,原因是因為scanf函數(shù)包含在 <stdio.h>這個庫里,是一個全局的函數(shù),而我們用scanf去命名全局變量,會報重定義的錯誤,這就導(dǎo)致了命名沖突,C語言是無法解決這個問題的,因此C++為了解決這個問題,引入了命名空間,來做名字的隔離
#include<stdio.h> int scanf = 10; int main() { printf("%x\n",scanf); }
命名空間 :
在C/C++中,變量、函數(shù)和我們后面要學(xué)到的類都是大量存在的,這些變量、函數(shù)和類的名稱將都存在于全局作用域中,可能會導(dǎo)致很多沖突。使用命名空間的目的是對標(biāo)識符的名稱進(jìn)行本地化,以避免命名沖突或名字污染,namespace關(guān)鍵字的出現(xiàn)就是針對這種問題的。
上面的代碼改正后如下
#include<stdio.h> namespace N { int scanf = 10; } int main() { printf("%x\n",scanf); // 以十六進(jìn)制打印出scanf函數(shù)的地址 printf("%x\n",N::scanf); // 以十六進(jìn)制打印出 N命名空間域里的 scanf變量 }
其中 N::scanf 中的 :: 為域作用限定符,表明要打印的 scanf 是 N命名空間域里的
了解了命名空間后,回到我們最開始的問題 using namespace std 是什么意思呢?
C++庫為了防止命名沖突,將自己庫里的東西都定義在一個名為 std 的命名空間里,要使用標(biāo)準(zhǔn)庫里的東西,有以下三種方式:
(1).指定命名空間
#include<iostream> int main() { std::cout<<"hello world"<<std::endl; }
(2).把std整個展開,即 using namespace std,雖然使用起來比較方便,但如果我們自己定義的東西跟庫里沖突了,就沒辦法解決了,因此在規(guī)范的工程項目中不推薦此種方式
#include<iostream> using namespace std; int main() { cout<<"hello world"<<endl; }
(3).對部分常用的庫里面的東西展開
#include<iostream> using std::cout; using std::endl; int main() { cout<<"hello world"<<endl; }
命名空間的幾點注意事項 :
(1). 命名空間里既可以定義變量,也可以定義函數(shù)
(2).命名空間可以嵌套定義
namespace A { int a; // 定義變量 int Add(int left,int right) // 定義函數(shù) { return left + right; } namespace B // 嵌套定義 { int b; int Sub(int left,int right) { return left - right; } } }
(3).在同一個工程里可以存在多個相同名稱的命名空間,在編譯時最終會合成到一個命名空間里,因此注意不要定義同名的變量或函數(shù),否則會報重定義的錯誤
三.缺省參數(shù)
(1).缺省參數(shù)的概念
缺省參數(shù)是聲明或定義函數(shù)時為函數(shù)的參數(shù)指定一個默認(rèn)值。在調(diào)用該函數(shù)時,如果沒有指定實參則采用該默認(rèn)值,否則使用指定的實參
void Testfunc(int a = 0) // 缺省參數(shù) { cout<<a<<endl; } int main() { Testfunc(10); // 使用給定的實參 Testfunc(); // 使用默認(rèn)值 }
(2). 缺省參數(shù)的分類
全缺省參數(shù) : 函數(shù)參數(shù)都指定了默認(rèn)值
void TestFunc(int a = 10,int b = 20,int c = 30) { cout<<a<<endl; cout<<b<<endl; cout<<c<<endl; }
半缺省參數(shù) : 函數(shù)參數(shù)部分指定了默認(rèn)值
void TestFunc(int a,int b = 20,int c = 30) { cout<<a<<endl; cout<<b<<endl; cout<<c<<endl; }
注意 :
(1).半缺省參數(shù)必須從右往左依次給出,不能間隔給出
void TestFunc(int a = 10,int b,int c = 20) // 錯誤寫法 { cout<<a<<endl; cout<<b<<endl; cout<<c<<endl; }
(2).缺省參數(shù)不能在聲明和定義中同時出現(xiàn)
a.h void TestFunc(int a = 10); a.c void TetsFunc(int a) { cout<<a<<endl; }
(3).缺省參數(shù)的值必須為常量或全局變量
四.函數(shù)重載
(1).函數(shù)重載的概念
C語言并不支持同名函數(shù)的存在,若定義了同名函數(shù)會報重定義的錯誤,C++在C語言的基礎(chǔ)上引入了函數(shù)重載的概念,即函數(shù)的名稱可以相同,但函數(shù)的參數(shù)列表不能相同(參數(shù)的類型,參數(shù)的個數(shù),參數(shù)的順序),函數(shù)的返回值不能作為重載的標(biāo)志,原因會在后面解釋
// 函數(shù)重載 int Add(int left,int right) { return left + right; } double Add(double left,double right) { return left + right; }
C++重載機制很好理解,但C++是怎么支持重載的呢?為什么C語言不支持重載呢?
在講述這個問題之前,我們要先回顧一下我們之前學(xué)的編譯鏈接過程
編譯可分為以下三個階段
1.預(yù)處理
預(yù)處理階段主要做的事情有以下幾點
(1).頭文件的展開
(2).進(jìn)行宏替換
(3).去掉注釋
(4).執(zhí)行條件編譯指令
經(jīng)過預(yù)處理階段后生成后綴名為.i的文件
2.編譯
編譯階段主要做的事情有以下幾點
(1).詞法分析
在詞法分析過程中,我們的源代碼程序會被輸入到掃描器中,掃描器會將源代碼的字符序列分割成不同的記號并分類,如關(guān)鍵字,標(biāo)識符,字面量,同時掃描器將分好類的記號存儲到對應(yīng)的位置,為后面的操作做好鋪墊
(2).語法分析
語法分析是通過建立一顆語法樹來實現(xiàn)的,我們所寫的語句是由多個表達(dá)式組成的,因此我們的語法樹是一顆以表達(dá)式為結(jié)點的樹,在語法分析的過程中,操作符的優(yōu)先級和結(jié)合性也被確定下來了,如果在語法分析過程中,出現(xiàn)了語法錯誤,編譯器就會報語法分析階段的錯誤
(3).語義分析
語法分析僅僅對語法進(jìn)行檢測,但并不知道語義是否正確,這就需要語義分析器上場了,語義分析階段主要做的是類型的匹配,轉(zhuǎn)換,比如我們將一個浮點型表達(dá)式賦值給一個整型表達(dá)式,需要進(jìn)行隱式類型轉(zhuǎn)換,語義分析需要完成這個步驟,將一個浮點型賦值給一個指針,語義分析會發(fā)現(xiàn)類型不匹配,編譯器會報錯,經(jīng)過語義分析階段后,語法樹的各個節(jié)點會被標(biāo)記上類型,需要類型轉(zhuǎn)換的,會插入相應(yīng)的轉(zhuǎn)換節(jié)點
經(jīng)過編譯階段后,生成了后綴名為.s的匯編代碼文件
3.匯編
匯編階段所做的事情比較簡單,匯編階段將編譯產(chǎn)生的匯編代碼文件轉(zhuǎn)換成二進(jìn)制機器指令
經(jīng)過匯編階段生成后綴名為.o的目標(biāo)文件
生成的目標(biāo)文件是按照ELF文件格式進(jìn)行存儲的,ELF文件由多個段組成,如.text(代碼段) .data(數(shù)據(jù)段) .symtab(符號表)等,這里重點要說的是符號表,符號表是一個數(shù)組,數(shù)組的元素是結(jié)構(gòu)體,結(jié)構(gòu)體描述了文件中符號的各種信息(符號名,符號值,符號類型等)
而C++支持函數(shù)重載,C不支持函數(shù)重載的原因是它們生成符號名時機制不同
C語言在生成符號表時,符號名是變量或函數(shù)名
C++在生成符號表時,符號名是函數(shù)名和形參列表的組合
如GCC編譯器的修飾規(guī)則如下 :
(1).所有的符號都以_Z開頭
(2).沒有嵌套的名字后跟函數(shù)名,函數(shù)名前是函數(shù)名的字符串長度,后跟參數(shù)類型首字母
(3).對于嵌套的名字(在命名空間或類里),后面緊跟'N',然后是命名空間或類的名稱,每個名字前是每個名字的字符串長度,后跟函數(shù)名,函數(shù)名前是函數(shù)名的字符串長度,后跟'E',后跟參數(shù)類型首字母
由此我們就知道了C++為什么支持重載,而C語言不支持重載,因為C++生成目標(biāo)文件以后,同名函數(shù)只要參數(shù)列表不同,符號名就不相同,而C語言生成目標(biāo)文件以后,同名函數(shù)的符號名相同,就會引發(fā)命名沖突
五.extern"C"
C++為了與C兼容,在符號的管理上,C++有一個用來聲明或定義C的符號的extern "C"關(guān)鍵字的用法
extern "C" { int func(int); int var; }
C++編譯器會將大括號里面的代碼當(dāng)成C語言的代碼來處理
六.引用
引用概念 : 引用不是新定義一個變量,而是給已存在變量取了一個別名,編譯器不會為引用變量開辟內(nèi)存空間,它和它引用的變量共用同一塊內(nèi)存空間。
使用: 類型& 引用變量名(對象名) = 引用實體
void TestRef() { int a = 10; int& ra = a;//<====定義引用類型 printf("%p\n", &a); printf("%p\n", &ra); // 打印的地址一樣 }
注意 : 引用類型必須和引用實體是同種類型的
引用特性 :
(1).引用必須初始化
(2).引用一旦初始化,不能被更改
(3).一個變量可以有多個引用
void TestRef() { int a = 10; // int& ra; // 該條語句編譯時會出錯 int& ra = a; int& rra = a; printf("%p %p %p\n", &a, &ra, &rra); // 地址都一樣 }
常引用 :
void TestConstRef() { const int a = 10; //int& ra = a; // 該語句編譯時會出錯,a為常量 const int& ra = a; // int& b = 10; // 該語句編譯時會出錯,b為常量 const int& b = 10; double d = 12.34; //int& rd = d; // 該語句編譯時會出錯,類型不同 const int& rd = d; }
const int a = 10; //int& ra = a; // 該語句編譯時會出錯,a為常量
編譯出錯的原因 :
原來a不能被修改,類型為 const int,但ra的類型為int,使權(quán)限提升了
double d = 12.34; //int& rd = d; // 該語句編譯時會出錯,類型不同 const int& rd = d;
編譯出錯的原因 :
在進(jìn)行類型轉(zhuǎn)換時,會產(chǎn)生一個臨時變量,rd是臨時變量的別名,但因為臨時變量具有常性,因此 int& rd = d;是錯誤的
引用做參數(shù)
void Swap(int& left,int& right) { int tmp = left; left = right; right = tmp; }
引用做返回值
// 正確寫法 int& Count() { static int n = 0; n++; // ... return n; }
下面代碼的運行結(jié)果是什么?
// 錯誤示范 int& Add(int a, int b) { int c = a + b; return c; } int main() { int& ret = Add(1, 2); Add(3, 4); cout << "Add(1, 2) is :"<< ret <<endl; // Add(1,2) is : 7 return 0; }
錯誤在于返回了局部變量的引用,Add函數(shù)返回的是局部變量c的引用,c出了作用域以后,c的空間就被操作系統(tǒng)回收了
引用和指針的區(qū)別
(1).引用必須初始化,指針可以不初始化
(2).引用初始化一個實體之后,不能再引用另外一個實體,指針指向一個實體后,可以再指向另外一個實體
(3).不存在空引用,存在空指針
(4).在語法上,引用是給一個變量取別名,指針取的變量的地址
(5).在sizeof中含義不同:引用結(jié)果為引用類型的大小,但指針始終是地址空間所占字節(jié)個數(shù)(32位平臺下占4個字節(jié))
(6).引用自加即引用的實體增加1,指針自加即指針向后偏移一個類型的大小
(7).有多級指針,但是沒有多級引用
(8). 訪問實體方式不同,指針需要顯式解引用,引用編譯器自己處理
(9). 引用比指針使用起來相對更安全
七.內(nèi)聯(lián)函數(shù)
內(nèi)聯(lián)函數(shù)概念 : 以inline修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù),編譯時C++編譯器會在調(diào)用內(nèi)聯(lián)函數(shù)的地方展開,沒有函數(shù)壓棧的開銷,內(nèi)聯(lián)函數(shù)提升程序運行的效率。
C語言為了小函數(shù)避免棧幀的消耗,提供了宏函數(shù)的支持,那為什么C++還要引入內(nèi)聯(lián)函數(shù)呢?
(1).宏函數(shù)在預(yù)處理階段會被替換掉,不能進(jìn)入函數(shù)內(nèi)部進(jìn)行調(diào)試
(2).宏函數(shù)不支持類型檢查,語法復(fù)雜,容易出錯
inline int Add(int x,int y) { return x + y; } int main() { int ret = Add(1,2); cout<<ret<<endl; }
八.auto關(guān)鍵字(C++11)
在早期C/C++中auto的含義是:使用auto修飾的變量,是具有自動存儲器的局部變量。
C++11中,標(biāo)準(zhǔn)委員會賦予了auto全新的含義即:auto不再是一個存儲類型指示符,而是作為一個新的類型指示符來指示編譯器,auto聲明的變量必須由編譯器在編譯時期推導(dǎo)而得。
int main() { int a = 10; auto b = a; // 類型聲明成auto,可以根據(jù)a的類型自動推導(dǎo)出b的類型 }
(1). auto與指針和引用結(jié)合起來使用
用auto聲明指針類型時,用auto和auto*沒有任何區(qū)別,但用auto聲明引用類型時則必須加&
int main() { int x = 10; auto a = &x; // 推導(dǎo)出 a 的類型為 int* auto* b = &x; // 推導(dǎo)出 b 的類型為 int* auto& c = x; // 推導(dǎo)出 c 的類型為 int 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; }
(2). 在同一行定義多個變量當(dāng)在同一行聲明多個變量時,這些變量必須是相同的類型,否則編譯器將會報錯,因為編譯器實際只對第一個類型進(jìn)行推導(dǎo),然后用推導(dǎo)出來的類型定義其他變量。
void TestAuto() { auto a = 1, b = 2; auto c = 3, d = 4.0; // 該行代碼會編譯失敗,因為c和d的初始化表達(dá)式類型不同 }
(3). auto不能作為函數(shù)的參數(shù)
// 此處代碼編譯失敗,auto不能作為形參類型,因為編譯器無法對a的實際類型進(jìn)行推導(dǎo) void TestAuto(auto a) {}
(4). auto不能直接用來聲明數(shù)組
void TestAuto() { int a[] = {1,2,3}; auto b[] = {4,5,6}; // 錯誤 }
(5).為了避免與C++98中的auto發(fā)生混淆,C++11只保留了auto作為類型指示符的用法
九.范圍for
C++11中引入了基于范圍的for循環(huán)。for循環(huán)后的括號由冒號“ :”分為兩部分:第一部分是范圍內(nèi)用于迭代的變量,第二部分則表示被迭代的范圍。
void TestFor() { int array[] = { 1, 2, 3, 4, 5 }; for(auto& e : array) e *= 2; for(auto e : array) cout << e << " "; // 2, 4, 6, 8, 10 }
以上就是C++入門(命名空間,缺省參數(shù),函數(shù)重載,引用,內(nèi)聯(lián)函數(shù),auto,范圍for)的詳細(xì)內(nèi)容,更多關(guān)于c++ 入門基礎(chǔ)知識的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語言實現(xiàn)掃雷小游戲(擴(kuò)展版可選擇游戲難度)
游戲目標(biāo)是找出所有沒有地雷的方格,完成游戲;要是按了有地雷的方格,游戲失?。煌婕铱蓸?biāo)記雷的位置,游戲以完成時間來評高低,并且用戶可以選擇游戲難度2019-10-10C++類和對象實戰(zhàn)之Date類的實現(xiàn)方法
C++ 標(biāo)準(zhǔn)庫沒有提供所謂的日期類型,C++ 繼承了C語言用于日期和時間操作的結(jié)構(gòu)和函數(shù),這篇文章主要給大家介紹了C++類和對象實戰(zhàn)之Date類的實現(xiàn)方法,需要的朋友可以參考下2021-12-12C++實現(xiàn)LeetCode(12.整數(shù)轉(zhuǎn)化成羅馬數(shù)字)
這篇文章主要介紹了C++實現(xiàn)LeetCode(12.整數(shù)轉(zhuǎn)化成羅馬數(shù)字),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C/C++ 中怎樣使用SetConsoleTextAttribute()函數(shù)來控制輸出字符的顏色
這篇文章主要介紹了C/C++ 中如何使用SetConsoleTextAttribute()函數(shù)來控制輸出字符的顏色,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03c++ 頭文件<cwchar>中常見函數(shù)的實現(xiàn)代碼
本文記錄了c++ 頭文件<cwchar>中常見函數(shù)的實現(xiàn),本文結(jié)合實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2023-12-12