摘要:中包含的即為命名空間的成員。使用輸入輸出更方便,不需增加數據格式控制,比如整形,字符可以連續輸出,表示換行缺省參數備胎,就是給汽車準備一個備用輪胎,一旦那個輪子爆胎或者出了問題,備用輪胎就方便及時地取而代之,汽車就不至于中途拋錨。
1.前言
2.C++關鍵字
3.命名空間
????3.1.命名空間的定義
????3.2.命名空間的使用
4.C++的輸入和輸出
5.缺省參數
????5.1.缺省參數的概念
????5.2.缺省參數的分類
????5.3.缺省參數的注意點
6.函數重載
????6.1.函數重載的概念
????6.2.函數重載的注意點
????6.3.為什么C++支持函數重載------名字修飾
????6.4.小結
7.extern “C”
8.引用
????8.1.引用的概念
????8.2.引用的特性
????8.3.常引用
????8.4.引用做參數
????8.5.引用做返回值
9.內聯函數
????9.1.概念
????9.2.特性
10.auto關鍵字(C++11)
11.范圍for
12.nullptr
相比于C語言的32個關鍵字,C++的關鍵字加至63個,很大程度上拓展了C語言的功能。
在C/C++中,變量,函數和類都是大量存在的。這些變量,函數,類都存在于全局作用域中,可能導致很多沖突。舉個例子,我們的命名的變量跟庫里的變量名,函數名沖突了。就會導致重命名的問題。在實際大型項目的開發中,還存在同事之間定義的變量/函數/類型命名沖突的情況。
比如說,在頭文件
為了對標識符的名稱進行本地化,以避免命名沖突和名字污染,namespace便應運而生了。
我們剛剛提到C++有63個關鍵字,幾乎比C語言多了一倍。那么,我們就來看看其中新增的一個關鍵字——namespace吧!
定義命名空間,我們就需要用到namespace關鍵字,后面跟命名空間的名字。然后接一對{}即可。{}中包含的即為命名空間的成員。
比如說,我和小許合作開發一款社交軟件,我們都在自己的文件里定義了全局變量cq。那在鏈接的過程中,就會報重命名的錯誤。于是,我們只好采用不同的命名空間來定義我們各自的cq變量啦!
我們在全局定義了命名空間C1和C2:
namespace C1 { int cq = 30;}namespace C2 { int cq = 80;}
不僅如此,我們還可以在命名空間里定義其他任意類型的變量以及函數:
namespace n1 { char ch; int a; double b; struct book { char name[20]; int price; int number; }; int Add(int x, int y) { return x + y; }}
甚至還可以嵌套定義命名空間:
namespace n2{ int a; int b; namespace n3 { int Sub(int x, int y) { return x - y; } }}
最后,同一個工程中允許存在多個相同名稱的命名空間,編譯器會最后合成到同一個命名空間中。
namespace C1 { int cq = 30;}namespace C1 { int cp = 40;}
好了,我們定義了各自的命名空間里定義了各自的cq,那用的時候怎么引用cq變量呢?
今有命名空間N
namespace N { int a = 30; int b = 40; int c = 50;}
我們有三種方法來使用命名空間N中定義的變量
using namespace
直接將命名空間中的變量全部展開到全局using namespace N;
優點:無腦方便
缺點:把定義的變量暴露出去了,容易造成命名污染
命名空間名稱
+域操作符 ::
在訪問時指定命名空間cout << N::rand <<endl;
優點:不存在命名污染
缺點:用起來太煩了
using
將部分命名空間成員展開using N::a;using N::b;
這樣既降低了命名污染的概率,又能在使用變量時偷懶了
初識一門新語言,我們按老規矩辦事!
#include using namespace std;int main(){ cout << "hello world!" << endl; return 0;}
于是,hello world!
便打印在了控制臺中了!
我們來認識一下C++的輸入輸出運算符
cin >> n;
cout << a[i];
注意:
cout<< "hello" << " " << "world" << "!" << endl;
備胎,就是給汽車準備一個備用輪胎,一旦那個輪子爆胎或者出了問題,備用輪胎就方便及時地取而代之,汽車就不至于中途拋錨。
顧名思義,這“感情備胎”就是給自己在感情的歸宿上像輪胎一樣,有多一個甚至多個備份,“感情備胎”一般多指愛情。
悄悄告訴你,C++的函數參數
也有備胎哦!
缺省參數是指在聲明或定義函數時給函數的參數指定一個默認值
。
在調用該函數時,如果沒有指定實參,就采用這個默認值,否則就采用實參。
比如說,我們希望malloc/realloc有默認開辟的大小。在希望使用默認值的時候缺省參數,不希望的時候傳一個自己想要的參數。
我們拿出以前寫過的棧的數據空間的初始化以及增容的代碼:
void StackBuy(Stack* ps, int init_num = 4){ assert(ps); ps->capacity = ps->capacity == 0 ? init_num : 2 * ps->capacity; StackDataType* tmp = (StackDataType*)realloc(ps->data, ps->capacity * sizeof(StackDataType)); if (tmp == NULL) { printf("realloc failed/n"); return; } ps->data = tmp;}
這里,我們讓棧的data的元素數量默認是4,但是如果你想要讓它是8或者16的時候,多傳一個參數就行了!
缺省參數可以分成全缺省參數和半缺省參數
void TestFunc(int a = 10, int b = 20, int c = 30){ cout<<"a = "<<a<<endl; cout<<"b = "<<b<<endl; cout<<"c = "<<c<<endl;}
void TestFunc(int a, int b = 10, int c = 20) { cout<<"a = "<<a<<endl; cout<<"b = "<<b<<endl; cout<<"c = "<<c<<endl;}
void TestFunc(int a, int b = 10, int c) { cout<<"a = "<<a<<endl; cout<<"b = "<<b<<endl; cout<<"c = "<<c<<endl;}
int a = 10
僅需在聲明或定義的地方寫一次就行了。
常量
或者全局變量
。自然語言中,一個詞可以有多重含義,人們可以通過上下文來判斷該詞真實的含義,即該詞被重載了。
學校期末考試考完了,出考場后:
學霸:“考試完了。”
學渣:“考試完了。”
嘿嘿,雖然這兩句話讀起來一樣,但表達的意思可不一樣哦!
C++里面也有一函數多義的情況!
函數重載:是函數的一種特殊情況,C++允許在同一作用域中
聲明幾個功能類似的同名函數
,這些同名函數的形參列表(參數個數
或 類型
或 順序
)必須不同,常用來處理實現功能類似數據類型不同的問題
int Add(int left, int right) { return left + right;}double Add(double left, double right) { return left + right;}long Add(long left, long right) { return left + right;}
int Add(int n1, int n2){ return n1 + n2;}int Add(int n1, int n2, int n3){ return n1 + n2 + n3;}
int Add(int n1, double n2){ return n1 + n2;}int Add(double n1, int n2){ return n1 + n2;}
請特別注意,返回值不同,函數名及參數相同的函數不能重載!
short Add(short left, short right) { return left + right;}int Add(short left, short right){ return left + right;}
這就不屬于函數重載
我們說函數重載是C語言不具有的功能,而C++添加了這個功能?
函數重載究竟是怎么實現的呢?
這就要從我們的底層函數調用講起了
在C/C++中,一個程序要運行起來,分為預處理,編譯,匯編,鏈接四個步驟
讓我們尤其來關注鏈接
這一步
鏈接時,當一個文件f1的某一行代碼調用了文件f2中的函數a時,編譯器看到f1調用了a,但是f1中找不到a的地址,于是,編譯器就去f2的符號表中尋找a的地址
,發現能夠找到,然后便把a和f1鏈接到一起
那么編譯器根據什么去尋找函數的呢?
答案是 通過編譯后的函數名修飾
,對應函數的地址,通過地址,最后找到函數
我們在Linux下分別使用gcc和g++編譯器看一下文件a.c和test.c
鏈接后的反匯編源碼
我們來看C語言編譯器gcc編譯鏈接后的結果:
我們可以看到,gcc編譯器的函數名修飾只與函數名本身有關而與函數參數無關,所以C語言不支持函數重載,因為即使重載了你也無法讓編譯器去通過參數的不同在鏈接時找到不同的函數!
我們來看C++編譯器g++編譯鏈接后的結果:
我們可以看到,g++編譯器通過函數名修飾規則將符號表中的函數符號修飾成了_Z3Addii
的形式
_Z3
代表函數名長度
Add
代表函數名
ii
代表有2個參數int和int
這樣參數不同的同名函數在符號表中被修飾成了不同的符號,這就能在鏈接時輕松找到不同函數了!
通過這里就理解了C語言沒辦法支持重載,因為同名函數沒辦法區分。
而C++是通過函數修飾規則來區 分,只要參數不同,修飾出來的名字就不一樣,就支持了重載。
另外我們也理解了,為什么函數重載要求參數不同!而跟返回值沒關系。
C++編譯器能識別C++函數名修飾規則,也能識別C函數名的修飾規則
有的時候,在C++工程中可能需要將某些函數按C的風格編譯,那么,我們只要在函數前面加 extern “C”
,意思是告訴編譯器,將該函數按C語言規則來編譯
請注意,extern “C”
要在函數聲明以及定義的地方都加上,不能只加一個地方,否則就會報錯!
先看一段代碼:
int main(){ int a = 10; int& ra = a;}
這里,ra就是a的引用。
引用不是新定義一個變量,而是給已存在變量取了一個別名,編譯器不會為引用變量開辟內存空間,它和它引用的變量共用同一塊內存空間。
比如,特朗普本名唐納德·特朗普,但在中國,被叫做懂王,懂王就是他的別名
引用的格式如下:
類型& 引用變量名(對象名) = 引用實體;
int& ra;
int a = 10; int& ra = a; int& ra2 = a; int& rra = ra;
int a = 10; int& ra = a; int b = 20; ra = b;
ra = b;并不是讓ra從a的引用變成b的引用,而是將b賦值給ra
首先我們提一句話:
引用時,別名的權限能夠減小或者不變,但不能放大
void TestConstRef() { const int a = 10; int& ra = a; //a被const修飾,表示a不能被改;而ra是a的引用,ra并沒有說明自己不能被改,這時ra的權限被放大了,所以編譯報錯}void TestConstRef() { const int a = 10; const int& ra = a; //這樣寫才是對的}
void TestConstRef() { int& ra = 10; //10是常量不能被修改,而ra卻是可以被修改,權限被放大了 const int& ra = 10; //這樣寫才是對的}
void TestConstRef() { double d =1.234; int& rd = d; //這里涉及到整型提升,將double轉換為int時,提升完了的值存放在一個具有常性的臨時變量里,所以右邊是常數,左邊是變量,左邊權限過大 const int& rd = d; //這樣寫才是對的}
所以引用前加const的好處是:
void Swap(int& left, int& right) { int temp = left; left = right; right = temp;}
先看一段錯誤的代碼
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; return 0;}
運行結果是7.
Why?
首先我們要知道函數被調用時會建立棧幀,函數被執行完時棧幀就會被銷毀,那么返回值是怎么被從Add函數中返回到main函數中的呢?你不是說Add函數 執行完return c; 之后棧幀就被銷毀了嗎?c是怎么被傳遞出來的呢?哦,傳值返回時,會為返回值開辟一個臨時變量,這個臨時變量還未還給操作系統,那么使用引用返回,就能把這塊地址上的值返回出去。這還是很危險的,萬一已經返還給操作系統了呢,內存已經被清空了呢?
于是,我們假設臨時變量的地址為0x8822ff44,第一次該地址上的值被置為3
同時,ret對應地址0x8822ff44
第二次調用Add,0x8822ff44上的值又被改為7
于是,ret對應的值就是7了
在C++中,內聯函數被用來替代宏函數
inline Add(int a, int b){ return a + b;}
以inline修飾的函數叫內聯函數,編譯時C++編譯器會在調用函數的地方展開,沒有建立棧幀的開銷,提升了程序運行的效率。
來看這樣一段代碼:
int a = 1;char b = "y";auto c = a;auto d = b;
auto關鍵字幫助我們通過右邊的賦值,自動判斷左邊聲明的變量的類型
優點:簡化了代碼
缺點:降低了代碼的可讀性
我們可以通過打印 typeid(變量).name() 來查看變量的類型
請注意:
int main() { int x = 10; auto a = &x; auto* b = &x; auto& c = x;}
int main(){ auto a = 3, c =4.0;}
void TestAuto(auto a) {}
void TestAuto() { int a[] = {1,2,3}; auto b[] = {4,5,6};}
auto不能用來聲明數組,因為編譯器不知道要申請多少字節的空間,后面的 3 究竟是short還是int還是long long?
對于一個有范圍的集合而言,由程序員來說明循環的范圍是多余的,有時候還會容易犯錯誤。
因此C++11中 引入了基于范圍的for循環。for循環后的括號由冒號“ :”分為兩部分:
第一部分是范圍內用于迭代的變量,
第二部分則表示被迭代的范圍。
注意:for循環迭代的范圍必須是確定的
int main() { int arr[] = { 1,2,3,4,5,6 }; for (auto e : arr) cout << e << endl;}
好的編程習慣應該是,在聲明一個變量的時候,給它賦一個合適的初值。
在對指針進行初始化的時候,我們在C語言中常常這樣做:
int p = NULL;
NULL在C語言里是空指針,值為0
,類型是(void*)
,代表地址0x00000000
而我們看到C的頭文件
#ifndef NULL #ifdef __cplusplus #define NULL 0 #else #define NULL ((void*)0)#endif#endif
這段代碼告訴我們,我們用C編譯器,NULL就是0處的地址;用C++編譯器,NULL就是一個字面常量0,沒有指針的屬性
以下情況下,NULL的使用就會產生麻煩:NULL被當作int 類型的0,而不是0x00000000
void f(int) { cout<<"f(int)"<<endl; }void f(int*){ cout<<"f(int*)"<<endl; }int main() { f(0); f(NULL); f((int*)NULL); return 0;}
于是,C++11引入了新關鍵字 nullptr
,代表0處地址
注意:
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/121539.html
文章目錄 一.快速入門二.C++ 語法三.省略命名空間四.C++輸出(打印文本)五.C++新行(換行)六.C++注釋 一.快速入門 運行如下程序: #include using namespace std;int main() { cout
摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進的編輯體驗,增強了語言服務。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經到來了,總結過去的 2017,相信小伙們一定有很多收獲...
摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進的編輯體驗,增強了語言服務。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經到來了,總結過去的 2017,相信小伙們一定有很多收獲...
摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進的編輯體驗,增強了語言服務。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經到來了,總結過去的 2017,相信小伙們一定有很多收獲...
閱讀 3343·2021-11-10 11:36
閱讀 3244·2021-10-08 10:21
閱讀 2841·2021-09-29 09:35
閱讀 2416·2021-09-22 16:06
閱讀 3958·2021-09-09 09:33
閱讀 1326·2019-08-30 15:44
閱讀 3170·2019-08-30 10:59
閱讀 2981·2019-08-29 15:32