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)識符的名稱進行本地化,以避免命名沖突或名字污染,namespace關(guān)鍵字的出現(xiàn)就是針對這種問題的。
上面的代碼改正后如下
#include<stdio.h>
namespace N
{
int scanf = 10;
}
int main()
{
printf("%x\n",scanf); // 以十六進制打印出scanf函數(shù)的地址
printf("%x\n",N::scanf); // 以十六進制打印出 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ù)指定一個默認值。在調(diào)用該函數(shù)時,如果沒有指定實參則采用該默認值,否則使用指定的實參
void Testfunc(int a = 0) // 缺省參數(shù)
{
cout<<a<<endl;
}
int main()
{
Testfunc(10); // 使用給定的實參
Testfunc(); // 使用默認值
}
(2). 缺省參數(shù)的分類
全缺省參數(shù) : 函數(shù)參數(shù)都指定了默認值
void TestFunc(int a = 10,int b = 20,int c = 30)
{
cout<<a<<endl;
cout<<b<<endl;
cout<<c<<endl;
}
半缺省參數(shù) : 函數(shù)參數(shù)部分指定了默認值
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).進行宏替換
(3).去掉注釋
(4).執(zhí)行條件編譯指令
經(jīng)過預(yù)處理階段后生成后綴名為.i的文件
2.編譯
編譯階段主要做的事情有以下幾點
(1).詞法分析
在詞法分析過程中,我們的源代碼程序會被輸入到掃描器中,掃描器會將源代碼的字符序列分割成不同的記號并分類,如關(guān)鍵字,標(biāo)識符,字面量,同時掃描器將分好類的記號存儲到對應(yīng)的位置,為后面的操作做好鋪墊
(2).語法分析
語法分析是通過建立一顆語法樹來實現(xiàn)的,我們所寫的語句是由多個表達式組成的,因此我們的語法樹是一顆以表達式為結(jié)點的樹,在語法分析的過程中,操作符的優(yōu)先級和結(jié)合性也被確定下來了,如果在語法分析過程中,出現(xiàn)了語法錯誤,編譯器就會報語法分析階段的錯誤
(3).語義分析
語法分析僅僅對語法進行檢測,但并不知道語義是否正確,這就需要語義分析器上場了,語義分析階段主要做的是類型的匹配,轉(zhuǎ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īng)過匯編階段生成后綴名為.o的目標(biāo)文件
生成的目標(biāo)文件是按照ELF文件格式進行存儲的,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;
編譯出錯的原因 :
在進行類型轉(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ù)處理階段會被替換掉,不能進入函數(shù)內(nèi)部進行調(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)在同一行聲明多個變量時,這些變量必須是相同的類型,否則編譯器將會報錯,因為編譯器實際只對第一個類型進行推導(dǎo),然后用推導(dǎo)出來的類型定義其他變量。
void TestAuto()
{
auto a = 1, b = 2;
auto c = 3, d = 4.0; // 該行代碼會編譯失敗,因為c和d的初始化表達式類型不同
}
(3). auto不能作為函數(shù)的參數(shù)
// 此處代碼編譯失敗,auto不能作為形參類型,因為編譯器無法對a的實際類型進行推導(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)的詳細內(nèi)容,更多關(guān)于c++ 入門基礎(chǔ)知識的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++中關(guān)鍵字const的詳細說明和使用介紹(最全)
const在C/C++中是十分重要的,如果單純理解為“常量”那么你的格局就小了,今天在這里給大家介紹一下const在C++中具體詳細的用法,需要的朋友可以參考下2025-03-03
C++實現(xiàn)LeetCode(114.將二叉樹展開成鏈表)
這篇文章主要介紹了C++實現(xiàn)LeetCode(114.將二叉樹展開成鏈表),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-07-07
C++中回調(diào)函數(shù)及函數(shù)指針的實例詳解
這篇文章主要介紹了C++中回調(diào)函數(shù)及函數(shù)指針的實例詳解的相關(guān)資料,希望通過本文能幫助到大家,讓大家理解掌握這部分內(nèi)容,需要的朋友可以參考下2017-10-10

