建設(shè)企業(yè)資質(zhì)雙網(wǎng)是哪兩個(gè)網(wǎng)站線上推廣平臺(tái)都有哪些
C++基礎(chǔ)
- 寫在開頭
- C++基礎(chǔ)
- 常用關(guān)鍵字
- using namespace
- 流插入和流提取操作符
- 內(nèi)聯(lián)函數(shù)(inline)
- 宏
- auto關(guān)鍵字 (c++11
- nullptr (c++11
- 缺省參數(shù)
- 函數(shù)重載
- 引用
寫在開頭
C++基礎(chǔ)部分我想介紹如下幾個(gè)關(guān)鍵點(diǎn):
- 常見關(guān)鍵字
- 命名空間的定義和使用
- 缺省參數(shù)
- 函數(shù)重載
- 引用、指針和引用的區(qū)別
- 內(nèi)聯(lián)函數(shù)
- 宏 ** C與C++結(jié)合
- 空指針NULL與nullptr的區(qū)別
可以看到C++的基礎(chǔ)部分,需要掌握的知識(shí)多為零碎細(xì)小的知識(shí),更需要總結(jié)和整理。
C++基礎(chǔ)
常用關(guān)鍵字
C語言中有32個(gè)關(guān)鍵字,而在C++98中,總共給出了63個(gè)關(guān)鍵字。所有的關(guān)鍵字如下所示:
asm | do | if | return | try | continue |
---|---|---|---|---|---|
auto | double | inline | short | typedef | for |
bool | dynamic_cast | int | signed | typeid | public |
break | else | long | sizeof | typename | throw |
case | enum | mutable | static | union | wchar_t |
catch | explicit | namespace | static_cast | unsigned | default |
char | export | new | struct | using | friend |
class | extern | operator | switch | virtual | register |
const | false | private | template | void | true |
const_cast | float | protected | this | volatile | while |
delete | goto | reinterpret_cast |
我們?cè)诖丝偨Y(jié)一些比較常用的關(guān)鍵字。
using namespace
命名空間使用的目的是對(duì)標(biāo)識(shí)符的名稱進(jìn)行本地化,避免命名沖突或命名污染
定義命名空間
namespace MySpace
{...
};
注意:
- 命名空間可以嵌套。
- 同一個(gè)工程可以存在多個(gè)相同名稱的命名空間,編譯器最終會(huì)合并成同一個(gè)。
- 定義一個(gè)命名空間就定義了一個(gè)新的作用域,命名空間中的所有內(nèi)容都局限于該作用域。
使用命名空間
使用命名空間有三種方法。
-
加命名空間名稱及作用域限定符
// namespace:MySpaceint main() {printf("%d", MySpace::a); }
-
使用using引入命名空間,或者引入命名空間中的某個(gè)成員
using MySpace::a; //引入某個(gè)成員 using MySpace; //引入整個(gè)命名空間
流插入和流提取操作符
- 流插入操作符:<<,流提取操作符:>>
- std是C++標(biāo)準(zhǔn)庫的命名空間名,如果使用標(biāo)準(zhǔn)庫中的函數(shù)或者其他定義,就需要使用命名空間std。
- 使用cout標(biāo)準(zhǔn)輸出對(duì)象和cin標(biāo)準(zhǔn)輸入對(duì)象,需要包含頭文件,并且要按照命名空間使用方法使用std。
- cout、cin是全局的流對(duì)象,endl是特殊的c++符號(hào),表示換行輸出,都包含在中。
- 使用C++的輸入輸出很方便,不需要手動(dòng)控制格式,而是由操作符自動(dòng)識(shí)別變量類型。
- 流插入和流提取運(yùn)算符在面對(duì)自定義類型時(shí)候,都涉及運(yùn)算符重載。
內(nèi)聯(lián)函數(shù)(inline)
內(nèi)聯(lián)函數(shù)是以inline 修飾的函數(shù),編譯時(shí)C++編譯器會(huì)在調(diào)用內(nèi)聯(lián)函數(shù)的地方展開,沒有函數(shù)調(diào)用建立棧幀的開銷,內(nèi)聯(lián)函數(shù)可以提升程序運(yùn)行的效率。
特性:
- inline是一種以空間換時(shí)間的做法,如果編譯器將函數(shù)當(dāng)成內(nèi)聯(lián)函數(shù)處理,在編譯階段,會(huì)用函數(shù)體替換函數(shù)調(diào)用。缺點(diǎn)是可能會(huì)讓目標(biāo)文件變大,優(yōu)點(diǎn)是少了函數(shù)調(diào)用的開銷,提高了程序的運(yùn)行效率。
- inline對(duì)于編譯器而言只是建議,就像register 一樣,不同編譯器對(duì)inline實(shí)現(xiàn)機(jī)制可能不同。一般來說,將函數(shù)規(guī)模小(代碼段短)、不是遞歸,且會(huì)頻繁調(diào)用的函數(shù)采用inline修飾,否則會(huì)忽略inline建議。
- inline不建議聲明和定義分離,分離會(huì)導(dǎo)致連接錯(cuò)誤,因?yàn)閕nline被展開,就沒有函數(shù)地址,鏈接找不到。
宏
宏的優(yōu)點(diǎn):增強(qiáng)代碼的復(fù)用性、提高性能;
宏的缺點(diǎn):不方便調(diào)試(在預(yù)編譯階段進(jìn)行了替換)、代碼可讀性差、可維護(hù)性差、容易誤用,沒有類型安全的檢查。
C++可以替換宏的技術(shù):
- 常量定義: 換用const 或者 enum
- 短小函數(shù)定義改用inline。
auto關(guān)鍵字 (c++11
隨著程序的復(fù)雜程度提高,類型名也越來越復(fù)雜,所以類型將會(huì)越來越難于拼寫、含義不明確導(dǎo)致容易出錯(cuò)。
早期的auto的含義是:使用auto修飾的變量,是具有自動(dòng)存儲(chǔ)器的局部變量,但無人使用。
c++11中,auto有了全新定義:auto作為一個(gè)新的類型指示符來指示編譯器,auto聲明的變量必須由編譯器在編譯的時(shí)期推導(dǎo)得到。
auto使用:
-
auto與指針和引用結(jié)合起來使用。
用auto聲明指針類型時(shí),用auto和auto* 沒有任何區(qū)別,但用auto聲明引用類型時(shí)必須加&
-
可在同一行定義多個(gè)變量
但是在同一行聲明多個(gè)變量時(shí),變量必須是相同類型,否則編譯器會(huì)報(bào)錯(cuò),因?yàn)榫幾g器實(shí)際上只對(duì)第一個(gè)變量的類型進(jìn)行推導(dǎo),并用推導(dǎo)出來的類型定義其他變量。
-
auto 也有不能使用的場(chǎng)景:
- auto不能作為函數(shù)的參數(shù)
- auto不能直接用來聲明函數(shù)
- auto舊的含義被舍棄了。
-
auto最常見的用法就是和范圍for或者lambda結(jié)合。
nullptr (c++11
指針空值:nullptr。
聲明一個(gè)變量時(shí)最好給變量一個(gè)合適的初始值。我們?cè)诙x指針時(shí),如果它沒有合法的指向,我們一般會(huì)定義其為:
int* p = NULL; //c
NULL實(shí)際上是一個(gè)宏,定義如下:
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void*)0)
#endif
#endif
可以看到,NULL可能被定義為字面常量0,或者被定義為無類型指針的常量。但是這些都會(huì)遇到麻煩:
void func(int)
{ cout << "func(int)" << endl; }
void func(int*)
{ cout << "func(int*)" << endl; }int main()
{func(0);func(NULL);func((int*)NULL);return 0;
}
程序的本意是用func(NULL) 調(diào)用指針版本的func(int*) 函數(shù),但是因?yàn)镹ULL 被定義成0,所以調(diào)用了func(int) 版本。
在C++98中,字面常量0既可以是整型數(shù)字,也可以是無類型指針void*常量,但是編譯器默認(rèn)情況下看0作為一個(gè)整型常量,所以如果要將其按照指針方式使用的話, 必須強(qiáng)轉(zhuǎn)(void🌟)0.
這無異給我們的使用帶來了困擾,所以c++11中添加了nullptr。
- nullptr表示指針空值,不用包含頭文件,因?yàn)槠涫亲鳛镃++11新關(guān)鍵字引入的。
- C++11中,sizeof(nullptr) 與 sizeof((void*)0)占用的字節(jié)數(shù)相同。
- 后續(xù)表示指針空值,一律用nullptr。
缺省參數(shù)
缺省參數(shù)是定義或者聲明函數(shù)時(shí)為函數(shù)的參數(shù)指定一個(gè)缺省值。如果在調(diào)用函數(shù)時(shí),沒有給出對(duì)應(yīng)的實(shí)參,就采用該形參的缺省值,否則使用指定的實(shí)參。
void func(int a = 10)
{cout << a << endl;
}
int main()
{func(1); //傳了,用自己傳的func(); //沒傳,用缺省的return 0;
}
缺省函數(shù)分類:
-
全缺省函數(shù)
函數(shù)的所有參數(shù)都有缺省值,意味著在調(diào)用函數(shù)的時(shí)候,可以不給任何實(shí)參。上面的func就是一個(gè)例子。
-
半缺省函數(shù)
void func(int a, int b = 10, int c = 20){cout << "a = " << a << endl;... }
上述就是半缺省函數(shù),代表著在調(diào)用函數(shù)的時(shí)候,可以不給出部分參數(shù)的值。有注意事項(xiàng):
- 半缺省參數(shù)必須從右往左依次給出,不能間隔。
- 缺省參數(shù)不能在函數(shù)的聲明和定義中同時(shí)出現(xiàn)。
- 缺省值必須是常量或者全局變量。
- C語言不支持缺省函數(shù)。
函數(shù)重載
函數(shù)重載是函數(shù)的一種特殊情況,C++允許在同一個(gè)作用域下聲明功能類似的同名函數(shù),同名函數(shù)的形參列表(包括參數(shù)個(gè)數(shù)或者類型或者類型順序)不同,常常用做處理實(shí)現(xiàn)功能類似數(shù)據(jù)類似的不同問題。接下來我們分開舉例。
-
參數(shù)類型不同
//打算實(shí)現(xiàn)int類型和double類型的Add函數(shù) int Add(int a, int b) {return a + b; } double Add(double a, double b) {return a + b; }
上述兩個(gè)函數(shù),參數(shù)的類型不同,但是函數(shù)名相同,這就構(gòu)成了函數(shù)重載。
-
參數(shù)個(gè)數(shù)不同
void f() { cout << "void f()" << endl;} void f(int a) { cout << "void f(int a)" << endl; }
這就是參數(shù)個(gè)數(shù)不同而函數(shù)名相同構(gòu)成的重載,如果我們調(diào)用f時(shí)不給任何參數(shù),就會(huì)調(diào)用上面的無參版本;如果調(diào)用f時(shí)任給一個(gè)int 值,就會(huì)調(diào)用下面的帶int 版本。
-
參數(shù)類型順序不同
void f(char ch, int a) {cout << "void f(char ch, int a)" << endl; } void f(int a, char ch) {cout << "void f(int a, char ch)" << endl; }
參數(shù)的類型順序如果稍有不同,也可以構(gòu)成重載。
C不支持函數(shù)重載,而C++支持,其原因就是:C++支持函數(shù)重載的原理是 名字修飾 (name mangling)
C/C++中程序的運(yùn)行需要經(jīng)過幾個(gè)步驟:預(yù)處理、編譯、匯編、鏈接。
舉個(gè)例子,現(xiàn)在有a.cc 、b.cc兩個(gè)文件,在 b.cc中定義了Add函數(shù),而在 a.cc中使用了Add函數(shù)。
編譯后鏈接之前,a.o 的目標(biāo)文件中沒有Add的函數(shù)地址,因?yàn)锳dd是在b.cc中定義的,所以Add的地址在b.o 中。
在鏈接時(shí),鏈接器看到a.o 調(diào)用Add,但是沒有Add的地址,就會(huì)到b.o 的符號(hào)表中找Add的地址,然后鏈接到一起。
鏈接時(shí),面對(duì)Add函數(shù),鏈接器會(huì)使用一個(gè)名字去找。每個(gè)編譯器的函數(shù)名修飾規(guī)則不同,gcc的函數(shù)名修飾過后不變(意味著不能同時(shí)出現(xiàn)兩個(gè)同名函數(shù)),g++函數(shù)名修飾過后,變成了 _z + 函數(shù)長度 + 函數(shù)名 + 類型首字母,編譯器將函數(shù)參數(shù)類型信息都添加到修改后的名字中。
正因如此:C語言無法支持函數(shù)重載,因?yàn)橥瘮?shù)無法區(qū)分;而C++時(shí)通過函數(shù)修飾規(guī)則來區(qū)分,只要參數(shù)不同(參數(shù)類型,參數(shù)個(gè)數(shù),參數(shù)類型順序),修飾出來的名字就不同,所以支持重載。
如果兩個(gè)函數(shù)的函數(shù)名和參數(shù)相同,而返回值不同,不構(gòu)成重載,因?yàn)檎{(diào)用時(shí)編譯器無法區(qū)分二者。編譯器區(qū)分規(guī)則是:_z + 函數(shù)長度 + 函數(shù)名 + 類型首字母。
引用
引用不是新定義一個(gè)變量,而是給已經(jīng)存在的變量取別名。變量和它的引用共用同一塊內(nèi)存空間。
引用特性:
-
引用在定義時(shí)必須初始化。
-
一個(gè)變量可以有多個(gè)引用。
-
引用一旦有了實(shí)體,就不能引用其他實(shí)體。
-
常引用: const 類型的對(duì)象,需要用常引用,即const + 類型+ & + 別名 = 實(shí)體。
const int a = 10; int & ra = a; //編譯時(shí)報(bào)錯(cuò),因?yàn)閍 是常量,如果不加const,可能會(huì)修改。 const int& ra = a; //正確寫法float b = 3.14; double& rb = b; //錯(cuò)誤,類型變了。 const double& rb = b; //可以,表示別名rb不能修改b的值。
使用場(chǎng)景:
-
做參數(shù)
void Swap(int& a, int& b) {int temp = a;a = b;b = temp; }
只有當(dāng)a 和b 是引用時(shí),才奏效,就跟我們當(dāng)時(shí)C語言傳指針一樣。
-
做返回值
int& Count() {static int n = 0;n++;return n; }
這里的n 是static靜態(tài)的,所以可以用傳引用返回,因?yàn)槌隽撕瘮?shù)的作用域,n還存在。如果我們定義一個(gè)普通的對(duì)象,如下:
int& count() {int n = 0;n ++;return n; }
可以發(fā)現(xiàn),出了函數(shù)的作用域,返回的對(duì)象已經(jīng)銷毀了,這時(shí)候必須使用傳值返回。
傳值和傳引用的區(qū)別:
傳值傳參或者傳值返回,函數(shù)不會(huì)直接傳遞參數(shù)或者將變量直接返回,而是傳遞這個(gè)參數(shù)或者返回值的臨時(shí)拷貝,因此這樣效率非常低,尤其是當(dāng)參數(shù)或者返回值類型大的時(shí)候,效率更低。
引用和指針的區(qū)別:
- 語法概念上:引用就是別名,沒有獨(dú)立空間,和引用實(shí)體共用一塊空間。
- 底層實(shí)現(xiàn)上:實(shí)際上是由空間的,因?yàn)橐檬前凑罩羔樂绞綄?shí)現(xiàn)的。
- 引用概念上定義一個(gè)變量的別名,而指針存儲(chǔ)一個(gè)變量的地址。
- 引用在定義時(shí)必須初始化,指針沒有要求。
- 引用在初始化引用一個(gè)實(shí)體之后,不能引用其他實(shí)體;指針可以在任意時(shí)刻指向同類型實(shí)體。
- 沒有NULL引用,但是有NULL指針。
- 在sizeof中含義不同,sizeof引用結(jié)果是引用類型的大小,指針始終是地址空間所占的字節(jié)。
- 引用++是引用實(shí)體++,指針++是指針向后偏移一個(gè)類型的大小。
- 有多級(jí)指針,沒多級(jí)引用。
- 訪問實(shí)體的方式不同,指針需要自己顯式解引用,引用則是編譯器自己處理。
- 引用比指針使用相對(duì)更安全。
以上就是C++入門時(shí)需要知道的基礎(chǔ)知識(shí)。