景區(qū)電子商務(wù)網(wǎng)站建設(shè)免費(fèi)推廣的網(wǎng)站平臺
1.C++關(guān)鍵字
🔥前言:
C++是在C的基礎(chǔ)之上,容納進(jìn)去了面向?qū)ο?/span>編程思想,并增加了許多有用的庫,以及編程范式等。熟悉C語言之后,對C++學(xué)習(xí)有一定的幫助。今天的主要目標(biāo):
1?? 補(bǔ)充C語言語法的不足,以及C++是如何對C語言設(shè)計(jì)不合理的地方進(jìn)行優(yōu)化的,比如:作用
域方面、IO方面、函數(shù)方面、指針方面、宏方面等。
2?? 為后續(xù)類和對象學(xué)習(xí)打基礎(chǔ)。
📢C++總計(jì)63個關(guān)鍵字,C語言32個關(guān)鍵字。
😋ps:下面我們只是看一下C++有多少關(guān)鍵字,不對關(guān)鍵字進(jìn)行具體的講解。后面我們學(xué)到以后再
細(xì)講。
2.命名空間
🌷在C/C++中,變量、函數(shù)和后面要學(xué)到的類都是大量存在的,這些變量、函數(shù)和類的名稱將都存在于全局作用域中,可能會導(dǎo)致很多沖突。使用命名空間的目的是對標(biāo)識符的名稱進(jìn)行本地化,以避免命名沖突或名字污染,namespace關(guān)鍵字的出現(xiàn)就是針對這種問題的。
#include <stdio.h>
#include <stdlib.h>
int rand = 10;
// C語言沒辦法解決類似這樣的命名沖突問題,所以C++提出了namespace來解決
int main()
{printf("%d\n", rand);
return 0;
}
// 編譯后后報錯:error C2365: “rand”: 重定義;以前的定義是“函數(shù)”
2.1 命名空間定義
定義命名空間,需要使用到namespace關(guān)鍵字,后面跟命名空間的名字,然后接一對{}即可,{}中即為命名空間的成員。
// 1. 正常的命名空間定義
namespace zwh
{// 命名空間中可以定義變量/函數(shù)/類型int rand = 10;int Add(int left, int right){return left + right;}struct Node{struct Node* next;int val;};
}
//2. 命名空間可以嵌套
// test.cpp
namespace N1
{
int a;
int b;
int Add(int left, int right){return left + right;}
namespace N2{int c;int d;int Sub(int left, int right){return left - right;}}
}
//3. 同一個工程中允許存在多個相同名稱的命名空間,編譯器最后會合成同一個命名空間中。
// ps:一個工程中的test.h和上面test.cpp中兩個N1會被合并成一個
// test.h
namespace N1
{
int Mul(int left, int right){return left * right;}
}
?注意:一個命名空間就定義了一個新的作用域,命名空間中的所有內(nèi)容都局限于該命名空間中。
2.2 命名空間使用
?命名空間中成員該如何使用呢?比如:
namespace bit
{// 命名空間中可以定義變量/函數(shù)/類型int a = 0;int b = 1;int Add(int left, int right){return left + right;}struct Node{struct Node* next;int val;};
}
int main()
{// 編譯報錯:error C2065: “a”: 未聲明的標(biāo)識符printf("%d\n", a);return 0;
}
命名空間的使用有三種方式:
- 加命名空間名稱及作用域限定符
int main()
{printf("%d\n", N::a);return 0;
}
- 使用using將命名空間中某個成員引入
using N::b;
int main()
{printf("%d\n", N::a);printf("%d\n", b);return 0;
}
- 使用using namespace 命名空間名稱引入
using namespce N;
int main()
{printf("%d\n", N::a);printf("%d\n", b);Add(10, 20);return 0;
}
3. C++輸入&輸出
👶新生嬰兒會以自己獨(dú)特的方式向這個嶄新的世界打招呼,C++剛出來后,也算是一個新事物,那C++是否也應(yīng)該向這個美好的世界來聲問候呢?🐣我們來看下C++是如何來實(shí)現(xiàn)問候的。
#include<iostream>
// std是C++標(biāo)準(zhǔn)庫的命名空間名,C++將標(biāo)準(zhǔn)庫的定義實(shí)現(xiàn)都放到這個命名空間中
using namespace std;
int main()
{cout<<"Hello world!!!"<<endl;return 0;
}
?說明:
1. 使用cout標(biāo)準(zhǔn)輸出對象(控制臺)和cin標(biāo)準(zhǔn)輸入對象(鍵盤)時,必須包含< iostream >頭文件以及按命名空間使用方法使用std。
2. cout和cin是全局的流對象,endl是特殊的C++符號,表示換行輸出,他們都包含在包<iostream >頭文件中。
3. <<是流插入運(yùn)算符,>>是流提取運(yùn)算符。
4. 使用C++輸入輸出更方便,不需要像printf/scanf輸入輸出時那樣,需要手動控制格式。C++的輸入輸出可以自動識別變量類型。
5. 實(shí)際上cout和cin分別是ostream和istream類型的對象,>>和<<也涉及運(yùn)算符重載等知識,這些知識我們我們后續(xù)才會學(xué)習(xí),所以我們這里只是簡單學(xué)習(xí)他們的使用。后面我們還會更深入的學(xué)習(xí)IO流用法及原理。
💎注意:
早期標(biāo)準(zhǔn)庫將所有功能在全局域中實(shí)現(xiàn),聲明在.h后綴的頭文件中,使用時只需包含對應(yīng)頭文件即可,后來將其實(shí)現(xiàn)在std命名空間下,為了和C頭文件區(qū)分,也為了正確使用命名空間,規(guī)定C++頭文件不帶.h;舊編譯器(vc 6.0)中還支持<iostream.h>格式,后續(xù)編譯器已不支持,因此推薦使用<iostream>+std的方式。
#include <iostream>
using namespace std;
int main()
{int a;double b;char c;// 可以自動識別變量的類型cin>>a;cin>>b>>c;cout<<a<<endl;cout<<b<<" "<<c<<endl;return 0;
}
// ps:關(guān)于cout和cin還有很多更復(fù)雜的用法,比如控制浮點(diǎn)數(shù)輸出精度,控制整形輸出進(jìn)制格式等
//等。因?yàn)镃++兼容C語言的用法,這些又用得不是很多,我們這里就不展開學(xué)習(xí)了。
std命名空間的使用慣例:
😳std是C++標(biāo)準(zhǔn)庫的命名空間,如何展開std使用更合理呢?
1. 在日常練習(xí)中,建議直接using namespace std即可,這樣就很方便。
2. using namespace std展開,標(biāo)準(zhǔn)庫就全部暴露出來了,如果我們定義跟庫重名的類型/對象/函數(shù),就存在沖突問題。該問題在日常練習(xí)中很少出現(xiàn),但是項(xiàng)目開發(fā)中代碼較多、規(guī)模大,就很容易出現(xiàn)。所以建議在項(xiàng)目開發(fā)中使用,像std::cout這樣使用時指定命名空間 + using std::cout展開常用的庫對象/類型等方式。
4.缺省參數(shù)
4.1 缺省參數(shù)概念
缺省參數(shù)是聲明或定義函數(shù)時為函數(shù)的參數(shù)指定一個缺省值。在調(diào)用該函數(shù)時,如果沒有指定實(shí)參則采用該形參的缺省值,否則使用指定的實(shí)參。
void Func(int a = 0)
{cout<<a<<endl;
}
int main()
{Func(); // 沒有傳參時,使用參數(shù)的默認(rèn)值Func(10); // 傳參時,使用指定的實(shí)參
return 0;
}
4.2 缺省參數(shù)分類
- 全缺省參數(shù)
void Func(int a = 10, int b = 20, int c = 30){cout<<"a = "<<a<<endl;cout<<"b = "<<b<<endl;cout<<"c = "<<c<<endl;}
- 半缺省參數(shù)
void Func(int a, int b = 10, int c = 20){cout<<"a = "<<a<<endl;cout<<"b = "<<b<<endl;cout<<"c = "<<c<<endl;}
?注意:
1. 半缺省參數(shù)必須從右往左依次來給出,不能間隔著給。
2. 缺省參數(shù)不能在函數(shù)聲明和定義中同時出現(xiàn)。
//a.hvoid Func(int a = 10);// a.cppvoid Func(int a = 20){}// 注意:如果生命與定義位置同時出現(xiàn),恰巧兩個位置提供的值不同,那編譯器就無法確定到底該
用那個缺省值。
3. 缺省值必須是常量或者全局變量。
4. C語言不支持(編譯器不支持)。
5. 函數(shù)重載
📺自然語言中,一個詞可以有多重含義,人們可以通過上下文來判斷該詞真實(shí)的含義,即該詞被重載了。
💭比如:以前有一個笑話,國有兩個體育項(xiàng)目大家根本不用看,也不用擔(dān)心。一個是乒乓球,一個
是男足。前者是“誰也贏不了!”,后者是“誰也贏不了!“
5.1函數(shù)重載概念
💠函數(shù)重載:是函數(shù)的一種特殊情況,C++允許在同一作用域中聲明幾個功能類似的同名函數(shù),這些同名函數(shù)的形參列表(參數(shù)個數(shù) 或 類型 或 類型順序)不同,常用來處理實(shí)現(xiàn)功能類似數(shù)據(jù)類型不同的問題。
#include<iostream>
using namespace std;
// 1、參數(shù)類型不同
int Add(int left, int right)
{cout << "int Add(int left, int right)" << endl;return left + right;
}
double Add(double left, double right)
{cout << "double Add(double left, double right)" << endl;return left + right;
}
// 2、參數(shù)個數(shù)不同
void f()
{cout << "f()" << endl;
}
void f(int a)
{cout << "f(int a)" << endl;
}
// 3、參數(shù)類型順序不同
void f(int a, char b)
{cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{cout << "f(char b, int a)" << endl;
}
int main()
{Add(10, 20);Add(10.1, 20.2);f();f(10);f(10, 'a');f('a', 10);return 0;
}
5.2 C++支持函數(shù)重載的原理--名字修飾(name Mangling)
🔱問:為什么C++支持函數(shù)重載,而C語言不支持函數(shù)重載呢?
在C/C++中,一個程序要運(yùn)行起來,需要經(jīng)歷以下幾個階段:預(yù)處理、編譯、匯編、鏈接。
1??實(shí)際項(xiàng)目通常是由多個頭文件和多個源文件構(gòu)成,而通過C語言階段學(xué)習(xí)的編譯鏈接,我們可以知道,【當(dāng)前a.cpp中調(diào)用了b.cpp中定義的Add函數(shù)時】,編譯后鏈接前,a.o的目標(biāo)文件中沒有Add的函數(shù)地址,因?yàn)锳dd是在b.cpp中定義的,所以Add的地址在b.o中。那么怎么辦呢?
2?? 所以鏈接階段就是專門處理這種問題,鏈接器看到a.o調(diào)用Add,但是沒有Add的地址,就會到b.o的符號表中找Add的地址,然后鏈接到一起。
3?? 那么鏈接時,面對Add函數(shù),鏈接接器會使用哪個名字去找呢?這里每個編譯器都有自己的函數(shù)名修飾規(guī)則。
4?? 由于Windows下vs的修飾規(guī)則過于復(fù)雜,而Linux下g++的修飾規(guī)則簡單易懂,下面我們使用g++演示了這個修飾后的名字。
5?? 通過下面我們可以看出gcc的函數(shù)修飾后名字不變。而g++的函數(shù)修飾后變成【_Z+函數(shù)長度+函數(shù)名+類型首字母】
- 采用C語言編譯器編譯后結(jié)果
結(jié)論:在linux下,采用gcc編譯完成后,函數(shù)名字的修飾沒有發(fā)生改變。
- 采用C++編譯器編譯后結(jié)果
結(jié)論:在linux下,采用g++編譯完成后,函數(shù)名字的修飾發(fā)生改變,編譯器將函數(shù)參數(shù)類型信息添加到修改后的名字中。
- Windows下名字修飾規(guī)則
對比Linux會發(fā)現(xiàn),windows下vs編譯器對函數(shù)名字修飾規(guī)則相對復(fù)雜難懂,但道理都是類似的,我們就不做細(xì)致的研究了。
6?? 通過這里就理解了C語言沒辦法支持重載,因?yàn)橥瘮?shù)沒辦法區(qū)分。而C++是通過函數(shù)修飾規(guī)則來區(qū)分,只要參數(shù)不同,修飾出來的名字就不一樣,就支持了重載。
7?? 如果兩個函數(shù)函數(shù)名和參數(shù)是一樣的,返回值不同是不構(gòu)成重載的,因?yàn)檎{(diào)用時編譯器沒辦法區(qū)分。
6.引用
6.1 引用概念
📕引用不是新定義一個變量,而是給已存在變量取了一個別名,編譯器不會為引用變量開辟內(nèi)存空
間,它和它引用的變量共用同一塊內(nèi)存空間。
比如:李逵,在家稱為"鐵牛",江湖上人稱"黑旋風(fēng)"。
💠類型& 引用變量名(對象名) = 引用實(shí)體;
void TestRef()
{int a = 10;int& ra = a;//<====定義引用類型printf("%p\n", &a);printf("%p\n", &ra);
}
?注意:引用類型必須和引用實(shí)體是同種類型的。
6.2 引用特性
1. 引用在定義時必須初始化
2. 一個變量可以有多個引用
3. 引用一旦引用一個實(shí)體,再不能引用其他實(shí)體
void TestRef()
{int a = 10;// int& ra; // 該條語句編譯時會出錯int& ra = a;int& rra = a;printf("%p %p %p\n", &a, &ra, &rra);
}
6.3 常引用
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;
}
6.4 使用場景
1. 做參數(shù)
void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}
2. 做返回值
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;return 0;
}
🔶注意:如果函數(shù)返回時,出了函數(shù)作用域,如果返回對象還在(還沒還給系統(tǒng)),則可以使用引用返回,如果已經(jīng)還給系統(tǒng)了,則必須使用傳值返回。
6.5 傳值、傳引用效率比較
以值作為參數(shù)或者返回值類型,在傳參和返回期間,函數(shù)不會直接傳遞實(shí)參或者將變量本身直接返回,而是傳遞實(shí)參或者返回變量的一份臨時的拷貝,因此用值作為參數(shù)或者返回值類型,效率是非常低下的,尤其是當(dāng)參數(shù)或者返回值類型非常大時,效率就更低。
#include <time.h>
struct A{ int a[10000]; };
void TestFunc1(A a){}
void TestFunc2(A& a){}
void TestRefAndValue()
{A a;// 以值作為函數(shù)參數(shù)size_t begin1 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc1(a);size_t end1 = clock();// 以引用作為函數(shù)參數(shù)size_t begin2 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc2(a);size_t end2 = clock();
// 分別計(jì)算兩個函數(shù)運(yùn)行結(jié)束后的時間cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}
💖值和引用的作為返回值類型的性能比較
#include <time.h>
struct A{ int a[10000]; };
A a;
// 值返回
A TestFunc1() { return a;}
// 引用返回
A& TestFunc2(){ return a;}
void TestReturnByRefOrValue()
{// 以值作為函數(shù)的返回值類型size_t begin1 = clock();for (size_t i = 0; i < 100000; ++i)TestFunc1();size_t end1 = clock();// 以引用作為函數(shù)的返回值類型size_t begin2 = clock();for (size_t i = 0; i < 100000; ++i)TestFunc2();size_t end2 = clock();// 計(jì)算兩個函數(shù)運(yùn)算完成之后的時間cout << "TestFunc1 time:" << end1 - begin1 << endl;cout << "TestFunc2 time:" << end2 - begin2 << endl;
}
通過上述代碼的比較,發(fā)現(xiàn)傳值和指針在作為傳參以及返回值類型上效率相差很大。
6.6 引用和指針的區(qū)別
在語法概念上引用就是一個別名,沒有獨(dú)立空間,和其引用實(shí)體共用同一塊空間。
int main()
{
int a = 10;
int& ra = a;
cout<<"&a = "<<&a<<endl;
cout<<"&ra = "<<&ra<<endl;
return 0;
}
在底層實(shí)現(xiàn)上實(shí)際是有空間的,因?yàn)?strong>引用是按照指針方式來實(shí)現(xiàn)的。
int main()
{
int a = 10;
int& ra = a;
ra = 20;
int* pa = &a;
*pa = 20;
return 0;
}
💯引用和指針的不同點(diǎn):
1. 引用概念上定義一個變量的別名,指針存儲一個變量地址。
2. 引用在定義時必須初始化,指針沒有要求
3. 引用在初始化時引用一個實(shí)體后,就不能再引用其他實(shí)體,而指針可以在任何時候指向任何一個同類型實(shí)體
4. 沒有NULL引用,但有NULL指針
5. 在sizeof中含義不同:引用結(jié)果為引用類型的大小,但指針始終是地址空間所占字節(jié)個數(shù)(32位平臺下占4個字節(jié))
6. 引用自加即引用的實(shí)體增加1,指針自加即指針向后偏移一個類型的大小
7. 有多級指針,但是沒有多級引用
8. 訪問實(shí)體方式不同,指針需要顯式解引用,引用編譯器自己處理
9. 引用比指針使用起來相對更安全
7. 內(nèi)聯(lián)函數(shù)
7.1 概念
以inline修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù),編譯時C++編譯器會在調(diào)用內(nèi)聯(lián)函數(shù)的地方展開,沒有函數(shù)調(diào)用建立棧幀的開銷,內(nèi)聯(lián)函數(shù)提升程序運(yùn)行的效率。
🔥如果在上述函數(shù)前增加inline關(guān)鍵字將其改成內(nèi)聯(lián)函數(shù),在編譯期間編譯器會用函數(shù)體替換函數(shù)的調(diào)用。
7.2 特性
1. inline是一種以空間換時間的做法,如果編譯器將函數(shù)當(dāng)成內(nèi)聯(lián)函數(shù)處理,在編譯階段,會用函數(shù)體替換函數(shù)調(diào)用,缺陷:可能會使目標(biāo)文件變大,優(yōu)勢:少了調(diào)用開銷,提高程序運(yùn)行效率。
2. inline對于編譯器而言只是一個建議,不同編譯器關(guān)于inline實(shí)現(xiàn)機(jī)制可能不同,一般建議:將函數(shù)規(guī)模較小(即函數(shù)不是很長,具體沒有準(zhǔn)確的說法,取決于編譯器內(nèi)部實(shí)現(xiàn))、不是遞歸、且頻繁調(diào)用的函數(shù)采用inline修飾,否則編譯器會忽略inline特性。
3. inline不建議聲明和定義分離,分離會導(dǎo)致鏈接錯誤。因?yàn)閕nline被展開,就沒有函數(shù)地址了,鏈接就會找不到。
📕【面試題】 宏的優(yōu)缺點(diǎn)?
優(yōu)點(diǎn):
1.增強(qiáng)代碼的復(fù)用性。
2.提高性能。
缺點(diǎn):
1.不方便調(diào)試宏。(因?yàn)轭A(yù)編譯階段進(jìn)行了替換)
2.導(dǎo)致代碼可讀性差,可維護(hù)性差,容易誤用。
3.沒有類型安全的檢查 。
C++有哪些技術(shù)替代宏?
1. 常量定義 換用const enum
2. 短小函數(shù)定義 換用內(nèi)聯(lián)函數(shù)
8. auto關(guān)鍵字(C++11)
8.1 類型別名思考
隨著程序越來越復(fù)雜,程序中用到的類型也越來越復(fù)雜,經(jīng)常體現(xiàn)在:
1. 類型難于拼寫
2. 含義不明確導(dǎo)致容易出錯
#include <string>
#include <map>
int main()
{std::map<std::string, std::string> m{ { "apple", "蘋果" }, { "orange",
"橙子" }, {"pear","梨"} };std::map<std::string, std::string>::iterator it = m.begin();while (it != m.end()){//....}return 0;
}
std::map<std::string, std::string>::iterator 是一個類型,但是該類型太長了,特別容易寫錯。聰明的同學(xué)可能已經(jīng)想到:可以通過typedef給類型取別名,使用typedef給類型取別名確實(shí)可以簡化代碼,但是typedef有會遇到新的難題:
typedef char* pstring;
int main()
{const pstring p1; // 編譯成功還是失敗?失敗,沒有初始化指針p1const pstring* p2; // 編譯成功還是失敗?成功,原句會被等效為char* const* p2;//*p2可以不初始化return 0;
}
在編程時,常常需要把表達(dá)式的值賦值給變量,這就要求在聲明變量的時候清楚地知道表達(dá)式的
類型。然而有時候要做到這點(diǎn)并非那么容易,因此C++11給auto賦予了新的含義。
8.2 auto簡介
在早期C/C++中auto的含義是:使用auto修飾的變量,是具有自動存儲器的局部變量,但遺憾的是一直沒有人去使用它,大家可思考下為什么?
C++11中,標(biāo)準(zhǔn)委員會賦予了auto全新的含義即:auto不再是一個存儲類型指示符,而是作為一個新的類型指示符來指示編譯器,auto聲明的變量必須由編譯器在編譯時期推導(dǎo)而得。
int TestAuto()
{return 10;
}
int main()
{int a = 10;auto b = a;auto c = 'a';auto d = TestAuto();cout << typeid(b).name() << endl;cout << typeid(c).name() << endl;cout << typeid(d).name() << endl;//auto e; 無法通過編譯,使用auto定義變量時必須對其進(jìn)行初始化return 0;
}
?【注意】
使用auto定義變量時必須對其進(jìn)行初始化,在編譯階段編譯器需要根據(jù)初始化表達(dá)式來推導(dǎo)auto的實(shí)際類型。因此auto并非是一種“類型”的聲明,而是一個類型聲明時的“占位符”,編譯器在編譯期會將auto替換為變量實(shí)際的類型。
8.3 auto的使用細(xì)則
1. auto與指針和引用結(jié)合起來使用
用auto聲明指針類型時,用auto和auto*沒有任何區(qū)別,但用auto聲明引用類型時則必須加&。
int main()
{int x = 10;auto a = &x;auto* b = &x;auto& c = x;cout << typeid(a).name() << endl;cout << typeid(b).name() << endl;cout << typeid(c).name() << endl;*a = 20;*b = 30;c = 40;return 0;
}
2. 在同一行定義多個變量
當(dāng)在同一行聲明多個變量時,這些變量必須是相同的類型,否則編譯器將會報錯,因?yàn)榫幾g器實(shí)際只對第一個類型進(jìn)行推導(dǎo),然后用推導(dǎo)出來的類型定義其他變量。
void TestAuto()
{auto a = 1, b = 2; auto c = 3, d = 4.0; // 該行代碼會編譯失敗,因?yàn)閏和d的初始化表達(dá)式類型不同
}
8.3 auto不能推導(dǎo)的場景
1. auto不能作為函數(shù)的參數(shù)
// 此處代碼編譯失敗,auto不能作為形參類型,因?yàn)榫幾g器無法對a的實(shí)際類型進(jìn)行推導(dǎo)
void TestAuto(auto a)
{}
2. auto不能直接用來聲明數(shù)組
void TestAuto()
{int a[] = {1,2,3};auto b[] = {4,5,6};
}
3. 為了避免與C++98中的auto發(fā)生混淆,C++11只保留了auto作為類型指示符的用法。
4. auto在實(shí)際中最常見的優(yōu)勢用法就是跟以后會講到的C++11提供的新式for循環(huán),還有l(wèi)ambda表達(dá)式等進(jìn)行配合使用。
9.基于范圍的for循環(huán)(C++11)
9.1 范圍for的語法
🎅在C++98中如果要遍歷一個數(shù)組,可以按照以下方式進(jìn)行:
void TestFor()
{
int array[] = { 1, 2, 3, 4, 5 };
for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)array[i] *= 2;
for (int* p = array; p < array + sizeof(array)/ sizeof(array[0]); ++p)cout << *p << endl;
}
💌對于一個有范圍的集合而言,由程序員來說明循環(huán)的范圍是多余的,有時候還會容易犯錯誤。因此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 << " ";
return 0;
}//注意:與普通循環(huán)類似,可以用continue來結(jié)束本次循環(huán),也可以用break來跳出整個循環(huán)。
9.2 范圍for的使用條件
1. for循環(huán)迭代的范圍必須是確定的。
對于數(shù)組而言,就是數(shù)組中第一個元素和最后一個元素的范圍;對于類而言,應(yīng)該提供begin和end的方法,begin和end就是for循環(huán)迭代的范圍。
注意:以下代碼就有問題,因?yàn)閒or的范圍不確定。
void TestFor(int array[])
{for(auto& e : array)cout<< e <<endl;
}
2. 迭代的對象要實(shí)現(xiàn)++和==的操作。(關(guān)于迭代器這個問題,以后會講,現(xiàn)在提一下,沒辦法講清楚,現(xiàn)在大家了解一下就可以了)
10.指針空值---nullptr(C++11)
1. 在使用nullptr表示指針空值時,不需要包含頭文件,因?yàn)閚ullptr是C++11作為新關(guān)鍵字引入的。
2. 在C++11中,sizeof(nullptr) 與 sizeof((void*)0)所占的字節(jié)數(shù)相同。
3. 為了提高代碼的健壯性,在后續(xù)表示指針空值時建議最好使用nullptr。