柚子快報(bào)邀請碼778899分享:開發(fā)語言 初識C++
柚子快報(bào)邀請碼778899分享:開發(fā)語言 初識C++
目錄
1、關(guān)鍵字
2、命名空間
2.1命名空間定義
2.2命名空間的使用有三種方式
2.3域
3、?C++輸入&輸出
4、缺省參數(shù)
5、函數(shù)重載
6、引用
6.1引用概念
6.2引用特征
?編輯
6.3常引用
6.4引用使用場景
6.5引用知識點(diǎn)
7、內(nèi)斂函數(shù)
7.1內(nèi)斂? ? ? ?
7.2內(nèi)斂函數(shù)特性
8.1auto自動推導(dǎo)數(shù)據(jù)類型
8.2auto語法
8.3auto使用細(xì)則
9、指針空值nullptr(C++11)
1、關(guān)鍵字
C++總計(jì)63個(gè)關(guān)鍵字,C語言32個(gè)關(guān)鍵字
2、命名空間
在C/C++中,變量、函數(shù)和后面要學(xué)到的類都是大量存在的,這些變量、函數(shù)和類的名稱將都存 在于全局作用域中,可能會導(dǎo)致很多沖突。使用命名空間的目的是對標(biāo)識符的名稱進(jìn)行本地化, 以避免命名沖突或名字污染,namespace關(guān)鍵字的出現(xiàn)就是針對這種問題的。
#include
#include
int rand = 10;
// C語言沒辦法解決類似這樣的命名沖突問題,所以C++提出了namespace來解決
int main()
{
printf("%d\n", rand);
return 0;
}
編譯后后報(bào)錯(cuò):error C2365: “rand”: 重定義;以前的定義是“函數(shù)”。
2.1命名空間定義
定義命名空間,需要使用到namespace關(guān)鍵字,后面跟命名空間的名字,然后接一對{ }即可,{ } 中即為命名空間的成員。
// wh是命名空間的名字
// 1. 正常的命名空間定義
namespace wh
{
// 命名空間中可以定義變量/函數(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. 同一個(gè)工程中允許存在多個(gè)相同名稱的命名空間,編譯器最后會合成同一個(gè)命名空間中。
// ps:一個(gè)工程中的test.h和上面test.cpp中兩個(gè)N1會被合并成一個(gè)
// test.h
namespace N1
{
int Mul(int left, int right)
{
return left * right;
}
}
2.2命名空間的使用有三種方式
?加命名空間名稱及作用域限定符? ? (指定訪問,不常用的使用指定訪問)? ??
int main()
{
printf("%d\n", N::a);
return 0;
}
使用using將命名空間中某個(gè)成員引入(指定展開,常用的使用指定展開) 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;
}
2.3域
局部域(影響生命周期)
全局域(影響生命周期)
命名空間域(全局的,不會影響生命周期)
????????都可以做到名字的隔離,不同域,可以定義同名的變量、函數(shù)、類型。
編譯器默認(rèn)查找順序:
? ? ? ? a.局部
? ? ? ? b.全局
? ? ? ? c.命名空間
b和c是同時(shí)進(jìn)行的。如果有命名沖突,就不需要展開命名空間。
3、?C++輸入&輸出
????????輸出‘Hello world!!!’
#include
// std是C++標(biāo)準(zhǔn)庫的命名空間名,C++將標(biāo)準(zhǔn)庫的定義實(shí)現(xiàn)都放到這個(gè)命名空間中
using namespace std;
int main()
{
cout<<"Hello world!!!"< return 0; } ?????????????說明: ????????????????????????????1. 使用cout標(biāo)準(zhǔn)輸出對象(控制臺)和cin標(biāo)準(zhǔn)輸入對象(鍵盤)時(shí),必須包含< iostream >頭文件 以及按命名空間使用方法使用std。 ????????????????????????????2. cout和cin是全局的流對象,endl是特殊的C++符號,表示換行輸出,他們都包含在包含< iostream >頭文件中。 ? ? ? ? ? ? ? ? ? ? ? ? ? ? 3. >是流提取運(yùn)算符。 ????????????????????????????4. 使用C++輸入輸出更方便,不需要像printf/scanf輸入輸出時(shí)那樣,需要手動控制格式。 C++的輸入輸出可以自動識別變量類型。 ????????????????????????????5. 實(shí)際上cout和cin分別是ostream和istream類型的對象,>>和<<也涉及運(yùn)算符重載等知識,這里只是初識。 注意:早期標(biāo)準(zhǔn)庫將所有功能在全局域中實(shí)現(xiàn),聲明在.h后綴的頭文件中,使用時(shí)只需包含對應(yīng) 頭文件即可,后來將其實(shí)現(xiàn)在std命名空間下,為了和C頭文件區(qū)分,也為了正確使用命名空間, 規(guī)定C++頭文件不帶.h;舊編譯器(vc 6.0)中還支持格式,后續(xù)編譯器已不支持,因 此推薦使用+std的方式。 #include 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; } 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這樣使用時(shí)指定命名空間 + using std::cout展開常用的庫對象/類型等方式。 4、缺省參數(shù) ????????缺省參數(shù)是聲明或定義函數(shù)時(shí)為函數(shù)的參數(shù)指定一個(gè)缺省值。在調(diào)用該函數(shù)時(shí),如果沒有指定實(shí)參則采用該形參的缺省值,否則使用指定的實(shí)參。 缺?。盒螀①x值。 //全缺?。ㄋ行螀①x值) void Fun2(int a = 10, int b = 20, int c = 30) { cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl << endl; } //半缺?。ㄓ械男螀⒉毁x值,根據(jù)傳參的順序,缺省只能從右開始) void Fun3(int a, int b = 20, int c = 30) { cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl << endl; } int main() { //Fun(2);//給a傳2,輸出為2 //Fun();//不給a傳值,輸出1,a的默認(rèn)參數(shù)。 Fun2(1, 2, 3); Fun2(1, 2); Fun2(1); Fun2(); Fun3(1); Fun3(1,2); Fun3(1,2,3); return 0; } 注意:必須順序傳值,不能跳躍傳值。 5、函數(shù)重載 函數(shù)重載:是函數(shù)的一種特殊情況,C++允許在同一作用域中聲明幾個(gè)功能類似的同名函數(shù),這 些同名函數(shù)的形參列表(參數(shù)個(gè)數(shù) 或 類型 或 類型順序)不同,常用來處理實(shí)現(xiàn)功能類似數(shù)據(jù)類型 不同的問題。 為什么c語言不支持函數(shù)重載: ??????????????c語言直接用函數(shù)名鏈接的時(shí)候去查找,c++用修飾后的函數(shù)名連接查找。 #include 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ù)個(gè)數(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; } ????????C語言沒辦法支持重載,因?yàn)橥瘮?shù)沒辦法區(qū)分。而C++是通過函數(shù)修 飾規(guī)則來區(qū)分,只要參數(shù)不同,修飾出來的名字就不一樣,就支持了重載。 ????????如果兩個(gè)函數(shù)函數(shù)名和參數(shù)是一樣的,返回值不同是不構(gòu)成重載的,因?yàn)檎{(diào)用時(shí)編譯器沒辦 法區(qū)分。 6、引用 6.1引用概念 ????????引用不是新定義一個(gè)變量,而是給已存在變量取了一個(gè)別名,編譯器不會為引用變量開辟內(nèi)存空 間,它和它引用的變量共用同一塊內(nèi)存空間 void TestRef() { int a = 10; int& ra = a;//<====定義引用類型 printf("%p\n", &a); printf("%p\n", &ra); } 注意:引用類型必須和引用實(shí)體是同種類型,引用++ra,a也變化,ra和a的地址相同。 6.2引用特征 ????????1. 引用在定義時(shí)必須初始化 ????????2. 一個(gè)變量可以有多個(gè)引用 ????????3. 引用一旦引用一個(gè)實(shí)體,再不能引用其他實(shí)體 #include void TestRef() { int a = 10; // int& ra; // 該條語句編譯時(shí)會出錯(cuò) int& ra = a; int& rra = a; printf("%p %p %p\n", &a, &ra, &rra); } 6.3常引用 ????????權(quán)限可以縮小可以平移,不可以放大。(僅對于指針和引用,值是一種拷貝) 6.4引用使用場景 ? ? ? ? 1.做參數(shù)(提高效率) void Swap(int& left, int& right) { int temp = left; left = right; right = temp; } a是x的別名,b是y的別名。? ? ? 指針也可以引用.? ? ???????? 類型轉(zhuǎn)換需要臨時(shí)變量? ? ? ?? ????????double? --->? int 類型轉(zhuǎn)換,需要一個(gè)臨時(shí)變量來存放double數(shù)據(jù),然后取整形的值給給r。(臨時(shí)變量是不能修改的,所以int& r要想引用,必須加const,否則就是權(quán)限放大) ????????x+y的值也需要放在臨時(shí)變量。 引用和指針的區(qū)別 ? ? ? ·? 語法上:引用不開空間,申請別名;指針在語法上要開空間,存的是地址。 ? ? ? ·?引用必須初始化,指針沒要求 ? ? ? ·? 引用在初始化時(shí)引用一個(gè)實(shí)體后,就不能再引用其他實(shí)體,而指針可以在任何時(shí)候指向任何一個(gè)同類型實(shí)體 ? ? ? ·? 沒有NULL引用,但有NULL指針 ? ? ? ·? 在sizeof中含義不同:引用結(jié)果為引用類型的大小,但指針始終時(shí)地址空間所占字節(jié)個(gè)數(shù)(32位平臺下占4個(gè)字節(jié)) ? ? ? ·? 引用自加即引用的實(shí)體增加,指針自加即指針向后偏移一個(gè)類型的大小。 2.做返回值(暫時(shí)不寫) 6.5引用知識點(diǎn) A.引用必須初始化,必須在定義引用時(shí)明確引用的是哪個(gè)變量或者對象,否則語法錯(cuò)誤,指針不初??始化時(shí)值為隨機(jī)指向 B.引用一旦定義時(shí)初始化指定,就不能再修改,指針可以改變指向 C.引用必須出示化,不能出現(xiàn)空引用,指針可以賦值為空 D.簡單粗暴的引用理解可以理解為被引用變量或?qū)ο蟮?別名" E.引用表面好像是傳值,其本質(zhì)也是傳地址,只是這個(gè)工作有編譯器來做,所以錯(cuò)誤 F.函數(shù)調(diào)用為了提高效率,常使用引用或指針作為函數(shù)參數(shù)傳遞變量或?qū)ο?/p> G.指針通過某個(gè)指針變量指向一個(gè)對象后,對它所指向的變量間接操作。程序中使用指針,程序的可讀性差;而引用本身就是目標(biāo)變量的別名,對引用的操作就是對目標(biāo)變量的操作 H.空指針沒有任何指向,刪除無害,引用是別名,刪除引用就刪除真實(shí)對象 7、內(nèi)斂函數(shù) c->宏函數(shù) #define ADD(a,b) ((a) + (b)) 為什么最后不加分號? ? ? ? ? 在c中, int main() { int ret = ADD(1,2); // int ret = ADD(1,2);;;;; 加多少個(gè)分號都可以 cout << ADD(1,2) < int x = 1,y = 2; ADD(x & y , x | y);//為什么要加內(nèi)括號:為了保證優(yōu)先級正確。 return 0; } ????????為什么要加分號 ????????為什么要加外括號:當(dāng)給ADD(1,2)乘一個(gè)數(shù)的時(shí)候 ????????為什么要加里面的括號:符號優(yōu)先級 7.1內(nèi)斂? ? ? ? ? ? ? ? 對于經(jīng)常調(diào)用的小函數(shù)。 inline int Add(int a,int b) { int ret = a + b; return a + b; } int main() { int c = Add(1,2);//內(nèi)斂函數(shù)Add,函數(shù)直接在這里展開. cout << c << endl; return 0; } Debug版本下面默認(rèn)不展開? ?-->? ?便于調(diào)試 relase版本太超前,不建議反匯編。 7.2內(nèi)斂函數(shù)特性 ? ? ? ? ·inline是一種以空間換時(shí)間的做法,如果編譯器將函數(shù)當(dāng)成內(nèi)聯(lián)函數(shù)處理,在編譯階段,會 用函數(shù)體替換函數(shù)調(diào)用,缺陷:可能會使目標(biāo)文件變大,優(yōu)勢:少了調(diào)用開銷,提高程序運(yùn) 行效率。 ? ? ? ? ·inline對于編譯器而言只是一個(gè)建議,不同編譯器關(guān)于inline實(shí)現(xiàn)機(jī)制可能不同,一般建 議:將函數(shù)規(guī)模較小、不是遞歸、且頻繁調(diào)用的函數(shù)采用inline修飾,否則編譯器會忽略inline特性。 ? ? ? ? ·inline不建議聲明和定義分離,分離會導(dǎo)致鏈接錯(cuò)誤。因?yàn)閕nline被展開,就沒有函數(shù)地址 了,鏈接就會找不到。直接在.h定義。 7.3內(nèi)斂函數(shù)知識點(diǎn) · 使用inline關(guān)鍵字的函數(shù)會不會被編譯器在調(diào)用處展開 ????????不一定,因?yàn)閕nline只是一種建議,需要看此函數(shù)是否能夠成為內(nèi)聯(lián)函數(shù) ·?頭文件中可以包含inline函數(shù)的聲明 ????????inline函數(shù)不支持聲明和定義分離開,因?yàn)榫幾g器一旦將一個(gè)函數(shù)作為內(nèi)聯(lián)函數(shù)處理,就會在調(diào)用位置展開,即該函數(shù)是沒有地址的,也不能在其他源文件中調(diào)用,故一般都是直接在源文件中定義內(nèi)聯(lián)函數(shù)的 · 可不可以在同一個(gè)項(xiàng)目的不同源文件內(nèi)定義函數(shù)名相同但實(shí)現(xiàn)不同的inline函數(shù) ????????inline函數(shù)會在調(diào)用的地方展開,所以符號表中不會有inline函數(shù)的符號名,不存在鏈接沖突。 ·?遞歸函數(shù)是不是都可以成為inline函數(shù) ????????比較長的函數(shù),遞歸函數(shù)就算定義為inline,也會被編譯器忽略 ???????? 8、auto關(guān)鍵字 8.1auto自動推導(dǎo)數(shù)據(jù)類型 ? ? ? ? 適合替換長類型(比較長的類型的定義,簡化代碼) ? ? ? ? 不能定義數(shù)組。 void main() { int a = 0; auto a = 0;//根據(jù)右側(cè),auto自動推導(dǎo)類型。 } 和typedef有相似的類型。 typedef的問題 typedef char* pstring; //字符指針類型pstring int main() { const pstring p1; //聲明一個(gè)pstring類型的常量指針, //因?yàn)橹羔槺旧硎强梢孕薷牡?,const修飾不能修改 const pstring* p2;// 不能通過p2指向的指針來修改它指向的數(shù)據(jù), //但可以通過p2來改變他的指針 return 0; } typeid作用:識別當(dāng)前類型 8.2auto語法 ? ? ? ? 遍歷數(shù)組 int main() { int array[] = { 1,2,3,4,5 }; //普通遍歷方法 for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i) { array[i] *= 2; } for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i) { cout << array[i] << " "; } cout << endl; //auto e遍歷方法 //自動取數(shù)在array,賦值給e //自動++,自動判斷結(jié)束 for (auto e : array) { cout << e << " "; } cout << endl; } e是數(shù)組array數(shù)據(jù)的臨時(shí)拷貝,修改e不會改變數(shù)組內(nèi)容,若想改變,則需要改為:auto& e auto并非是一種“類型”的聲明,而是一個(gè)類型聲明時(shí)的“占位符”,編譯器在編 譯期會將auto替換為變量實(shí)際的類型。 與普通循環(huán)類似,可以用continue來結(jié)束本次循環(huán),也可以用break來跳出整個(gè)循環(huán) ? 8.3auto使用細(xì)則 ? ? ? ? 1.auto與指針和引用結(jié)合起來使用 ? ? ? ? 用auto聲明指針類型時(shí),用auto和auto*沒有區(qū)別,但用auto聲明引用類型時(shí)則必須加&。 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.在同一行定義多個(gè)變量 ????????在同一行聲明多個(gè)變量時(shí),這些變量必須是相同的類型,否則編譯器將會報(bào)錯(cuò),因?yàn)榫幾g 器實(shí)際只對第一個(gè)類型進(jìn)行推導(dǎo),然后用推導(dǎo)出來的類型定義其他變量。 ? void TestAuto() { auto a = 1, b = 2; auto c = 3, d = 4.0; // 該行代碼會編譯失敗,因?yàn)閏和d的初始化表達(dá)式類型不同 } 8.4auto不能使用場景 ? ? ? ? 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}; } 9、指針空值nullptr(C++11) ????????在良好的C/C++編程習(xí)慣中,聲明一個(gè)變量時(shí)最好給該變量一個(gè)合適的初始值,否則可能會出現(xiàn)不可預(yù)料的錯(cuò)誤,比如未初始化的指針。如果一個(gè)指針沒有合法的指向,我們基本都是按照如下 方式對其進(jìn)行初始化: void TestPtr() { int* p1 = NULL; int* p2 = 0; // …… } NULL實(shí)際是一個(gè)宏,NULL可能被定義為字面常量0,或者被定義為無類型指針(void*)的常量。 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; } ????????在這里我們可以看到,0為int類型,NULL為int類型,如果NULL要想變成int*類型 ,必須強(qiáng)制類型轉(zhuǎn)化。 ????????在C++98中,字面常量0既可以是一個(gè)整形數(shù)字,也可以是無類型的指針(void*)常量,但是編譯器默認(rèn)情況下將其看成是一個(gè)整形常量,如果要將其按照指針方式來使用,必須對其進(jìn)行強(qiáng)轉(zhuǎn)(void*)0。 注意: ????????1. 在使用nullptr表示指針空值時(shí),不需要包含頭文件,因?yàn)閚ullptr是C++11作為新關(guān)鍵字引入 的。 ????????2. 在C++11中,sizeof(nullptr) 與 sizeof((void*)0)所占的字節(jié)數(shù)相同。 ????????3. 為了提高代碼的健壯性,在后續(xù)表示指針空值時(shí)建議最好使用nullptr。 本集完。 ? 柚子快報(bào)邀請碼778899分享:開發(fā)語言 初識C++ 文章來源
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。