C++98的關鍵字:
單個詳解:(從a~z排序解釋)
- asm
asm:是語句分隔符,後面大括號其中放彙編指令。
_asm { MOV a,1 MOV b,2 ADD c,a,b }
-
auto
這裏只說明C++11的新定義。
C++11中,標準委員會賦予了auto全新的含義即:auto不再是一個存儲類型指示符,而是作爲一個新的類型指示符來指示編譯器,auto聲明的變量必須由編譯器在編譯時期推導而得。
int a = 10; auto b = a; //得到b int類型 auto c = 'a'; //得到c char類型
注意:使用auto定義變量時必須對其進行初始化,在編譯階段編譯器需要根據初始化表達式來推導auto的實際類 型。因此auto並非是一種“類型”的聲明,而是一個類型聲明時的“佔位符”,編譯器在編譯期會將auto替換爲變 量實際的類型。
auto一些應用場景:
- 在引用、指針的使用
用auto聲明指針類型時,用auto和auto*沒有任何區別,但用auto聲明引用類型時則必須加&
int x = 10; auto a = &x; //auto是:int* auto* b = &x; //auto是:int auto& c = x; //auto是int //用auto聲明指針類型時,用auto和auto*沒有任何區別,但用auto聲明引用類型時則必須加&
- 在同一行定義多個變量
當在同一行聲明多個變量時,這些變量必須是相同的類型,否則編譯器將會報錯,因爲編譯器實際只對第一個 類型進行推導,然後用推導出來的類型定義其他變量。
auto a = 1, b = 2; auto c = 3, d = 4.0; // 該行代碼會編譯失敗,因爲c和d的初始化表達式類型不同
- auto在實際中常見的優勢用法就是:範圍for循環,還有lambda表達式等進行配合使用。
範圍for的語法:
for循環後的括號由冒號“ :”分爲兩部分:第一部分是範圍內用於迭代的變量,第二部分則表示被迭代的範圍。
舊式的遍歷數組方式:
void Test() { 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; }
利用auto關鍵字:
注意:與普通循環類似,可以用continue來結束本次循環,也可以用break來跳出整個循環。
void Test() { int array[] = { 1, 2, 3, 4, 5 }; for(auto& e : array) e *= 2; for(auto e : array) cout << e << " "; return 0; }
使用條件:for循環迭代的範圍必須是確定的;迭代的對象要實現++和==的操作。
auto不能用的場景:
- auto不能作爲函數的參數
- auto不能直接用來聲明數組
- 實例化模板時不能使用auto作爲模板參數
- bool,ture,false
bool類型取值範圍僅有兩個值:true和false。在做邏輯運算時,默認非零即爲ture。
- break,continue,goto
break 直接跳出當前的循環,從當前循環外面開始執行,忽略循環體中任何其他語句和循環條件測試。他只能跳出一層循環,如果你的循環是嵌套循環,那麼你需要按照你嵌套的層次,逐步使用break來跳出。
continue也是終止當前的循環過程,但他並不跳出循環,而是繼續往下判斷循環條件執行語句。他只能結束循環中的一次過程,但不能終止循環繼續進行。
goto用於無條件跳轉到函數內的標號。程序較少使用goto,更多使用循環代替,因爲代碼的可讀性,結構性都會變差。
- case,default,switch
分支語句中。switch是分支語句的起始位置,根據switch條件跳轉到case標號,不滿足的跳到defalut標記的分支上。
- catch,throw,try
異常處理中使用。try指定try塊的起始,try塊後的catch可以捕獲異常。異常由throw拋出。throw在函數中還表示動態異常規範,但在C++11中被標記爲過時(由noexcept部分取代)。
- char,wchar_t
表示字符型和寬字符型這些整數類型(屬於基本類型),但一般只專用於表示字符
- struct,class,union
用於類型聲明。class是一般的類類型。struct在C++中是特殊的類類型,聲明中僅默認隱式成員和基類訪問限定與class不同(struct是public,class是private)。
union是聯合體類型。滿足特定條件類類型——POD struct或POD union可以和中的struct和union對應兼容。
class還有個用途是在模版類型聲明中作爲表示模版類型參數或模版模版參數的語法的必要組成部分。也可被typename代替。
- do,for,while
循環語句的組成部分。C++支持do-while循環、for循環和while循環。C++11新增了範圍for循環,用 :分隔聲明的對象和指定循環的範圍。(auto關鍵字的使用)
-
const、volatile
const修飾非成員變量:
const全局變量:編譯器不允許對const全局變量的改動。const表示只讀類型(指定類型安全性,保護對象不被意外修改)
const局部變量:
解決這個問題的方法是volatile關鍵字。
volatile關鍵字使得程序每次直接去內存中讀取變量值而不是讀寄存器值,這個作用在解決一些不是程序而是由於別的原因修改了變量值時非常有用。
volatile指定被修飾的對象類型的讀操作是副作用(因此讀取不能被隨便優化合並,適合映射I/O寄存器等)。
volatile:
- a、當讀取一個變量時,爲提高存取速度,編譯器優化時有時會先把變量讀取到一個寄存器中,以後再取變量值時,就直接從寄存器中取值。
- b、優化器在用到volatile變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存到寄存器裏的備份。
- c、volatile適用於多線程應用中被幾個任務共享的變量。
cosnt修飾指針:
const修飾指針,涉及到兩個很重要的概念,頂層const和底層cosnt。
頂層const(top-level const):指針本身是個常量
底層const(low-level const):指針指向對象是一個常量
int a = 1; int b = 2; const int* p1 = &a; int* const p2 = &a;
根據從內到外,由近到遠讀符號的規則:
p1依次解讀爲:p1是個指針(*),指向一個int型對象(int),該對象是個常量(const)。 因此這是一個底層cosnt。
p2依次解讀爲:p2是個常量(const),p2是個指針(*),指向一個int對象(int)。 因此這是一個頂層const。
const修飾函數參數
const修飾參數是爲了防止函數體內可能會修改參數原始對象。因此,有三種情況可討論:
函數參數爲值傳遞:值傳遞(pass-by-value)是傳遞一份參數的拷貝給函數,因此不論函數體代碼如何運行,也只會修改拷貝而無法修改原始對象,這種情況不需要將參數聲明爲const。
函數參數爲指針:指針傳遞(pass-by-pointer)只會進行淺拷貝,拷貝一份指針給函數,而不會拷貝一份原始對象。因此,給指針參數加上頂層const可以防止指針指向被篡改,加上底層const可以防止指向對象被篡改。
函數參數爲引用:引用傳遞(pass-by-reference)有一個很重要的作用,由於引用就是對象的一個別名,因此不需要拷貝對象,減小了開銷。這同時也導致可以通過修改引用直接修改原始對象(畢竟引用和原始對象其實是同一個東西),因此,大多數時候,推薦函數參數設置爲pass-by-reference-to-const。給引用加上底層const,既可以減小拷貝開銷,又可以防止修改底層所引用的對象。
const成員函數
const實施與成員函數上,只要是防止成員函數修改類對象的內容。良好的類接口設計應該確保如果一個成員函數功能上不需要修改對象的內容,該成員函數應該加上const修飾。
如果const成員函數想修改成員變量值,可以用mutable修飾目標成員變量。
如果一個類對象爲const 對象,語義上說明該對象的值不可改變,因此該const對象只能調用const成員函數,因爲非const成員函數不能保證不修改對象值,編譯器會禁止這種會造成隱患的行爲。
mutable
mutable也是爲了突破const的限制而設置的。被mutable修飾的變量,將永遠處於可變的狀態,即使在一個const函數中。
-
new,delete
new、delete屬於操作符。new表示向內存申請一段新的空間,申請失敗會拋出異常。new會先調用operator new函數,再在operator new函數裏調用malloc函數分配空間,然後再調構造函數。
delete不僅會清理資源,還會釋放空間。delete先調用析構函數,其次調用operator delete函數,最後在operator delete函數裏面調用free函數。
malloc申請內存失敗會返回空。free只是清理了資源,並沒有釋放空間。
- if,else
- 數值類型,如 int、double、float、short、long、signed、unsigned
這裏要說明的是:char:1字節;short:3字節;int:4字節;long:4字節;float:4字節;double:8字節
- enum
構成枚舉類型名的關鍵字。
-
export
使用該關鍵字可實現模板函數的外部調用。對模板類型,可以在頭文件中聲明模板類和模板函數;在代碼文件中,使用關鍵字export來定義具體的模板類對象和模板函數;然後在其他用戶代碼文件中,包含聲明頭文件後,就可以使用該這些對象和函數。
-
extern
當出現extern “C”時,表示 extern “C”之後的代碼按照C語言的規則去編譯;當extern修飾變量或函數時,表示其具有外部鏈接屬性,即其既可以在本模塊中使用也可以在其他模塊中使用。
-
friend
友元。使其不受訪問權限控制的限制。例如,在1個類中,私有變量外部是不能直接訪問的。可是假如另外1個類或函數要訪問本類的1個私有變量時,可以把這個函數或類聲明爲本類的友元函數或友元類。這樣他們就可以直接訪問本類的私有變量。
-
inline
內聯函數,在編譯時將所調用的函數代碼展開直接嵌入到主調函數中。這只是一種建議,編譯器可以不接受;有循環、遞歸、代碼過長的時候就不會進行展開。
- namespace
- public、protected、private
這三個都爲權限修飾符。public爲公有的,訪問不受限制;protected爲保護的,只能在本類和友元中訪問;private爲私有的,只能在本類、派生類和友元中訪問。
-
register
提示編譯器儘可能把變量存入到CPU內部寄存器中。
- return
-
static
可修飾變量(靜態全局變量,靜態局部變量),也可以修飾函數和類中的成員函數。static修飾的變量的週期爲整個函數的生命週期。具有靜態生存期的變量,只在函數第一次調用時進行初始化,在沒有顯示初始化的情況下,系統把他們初始化爲0。
- 修飾局部變量:static修飾的靜態局部變量只執行一次,而且延長了局部變量的生命週期,隨程序的結束而結束。
- 修飾全局變量:被static修飾的全局變量只能在本文件中訪問,不能再其它文件中訪問。
- 修飾函數:修飾的函數只能在本文件中調用,不能被其它文件調用。
static修飾的局部變量存放在全局數據區的靜態變量區,初始化的時候自動初始化爲0;
- 不想被釋放的時候,可以使用static修飾。比如修飾函數中存放棧空間的數組,如果不想讓這個數組在函數調用時結束則可用static修飾。
- 考慮到數據安全性(當程序想要使用全局變量的時候應該考慮使用static)
static修飾靜態數據成員
- 靜態數據成員可以實現多個對象之間的數據共享,它是類的所有對象的共享成員,它在內存中只佔一份空間,如果改變它的值,則各對象中這個數據成員的值都被改變。
- 靜態數據成員是在程序開始運行時被分配空間,到程序結束之後才釋放,只要類中指定了靜態數據成員,即使不定義對象,也會爲靜態數據成員分配空間。
- 靜態數據成員可以被初始化,但只能在類體外進行初始化,若爲靜態數據成員賦初值,則編譯器會自動爲其初始化爲0.
- 靜態數據成員既可以通過對象名引用,也可以通過類名引用。
static修飾靜態成員函數
- 靜態成員函數和靜態數據成員一樣,他們都屬於類的靜態成員,而不是對象成員。
- 非靜態成員函數有this指針,而靜態成員函數沒有this指針。
- 靜態成員函數主要用來訪問靜態數據成員而不能訪問非靜態成員。
-
sizeof
這裏說明 sizeof 和 strlen 的區別。
strlen是用來計算字符串的長度,遇到第一個NULL('\0')爲止,不包括‘\0’。
sizeof是用來計算變量或者對象、類型所佔字節的多少。
char s1[] = "hello"; char* s2 = "hello"; char s3[10] = "hello"; sizeof(s1) = 5 strlen(s1) = 5 sizeof(s2) = 4 (在32位系統是4,在64系統是8) strlen(s2) = 5 sizeof(s3) = 1*10 strlen(s3) = 5 int a[50]; //sizeof(a)=4*50=200; //求數組所佔的空間大小 int *a = new int[50]; // sizeof(a)=4; a爲一個指針,sizeof(a)是求指針的大小,在32位系統中,當然是佔4個字節
總結如下,當參數分別如下時,sizeof返回的值表示的含義如下:
- 數組——編譯時分配的數組空間大小;
- 指針——存儲該指針所用的空間大小(在32位系統是4,在64系統是8);
- 類型——該類型所佔的空間大小;
- 對象——對象的實際佔用空間大小;
- 函數——函數的返回類型所佔的空間大小。函數的返回類型不能是void
strlen是一個函數,並且所傳入的參數必須是char*,發生在運行時刻。
sizeof只關心這塊內存的大小,不關心這塊內存存放了什麼數據,strlen只關心這塊內存存放的數據,不關心這塊內存的大小,直到遇到第一個NULL爲止。
char* s = "0123456789"; sizeof(s); //結果 4 ===》s是指向字符串常量的字符指針 sizeof(*s); //結果 1 ===》*s是第一個字符 strlen(s); //結果 10 ===》有10個字符,strlen是個函數內部實現是用一個循環計算到\0爲止之前 strlen(*s); //結果 10 ===》錯誤 char s[] = "0123456789"; sizeof(s); //結果 11 ===》s是數組,計算到\0位置,因此是10+1 strlen(s); //結果 10 ===》有10個字符,strlen是個函數內部實現是用一個循環計算到\0爲止之前 sizeof(*s); //結果 1 ===》*s是第一個字符 char s[100] = "0123456789"; sizeof(s); //結果是100 ===》s表示在內存中的大小 100×1 strlen(s); //結果是10 ===》strlen是個函數內部實現是用一個循環計算到\0爲止之前 int s[100] = "0123456789"; sizeof(s); //結果 400 ===》s表示再內存中的大小 100×4 strlen(s); //錯誤 ===》strlen的參數只能是char* 且必須是以‘\0‘結尾的 char q[]="abc"; char p[]="a\n"; sizeof(q),sizeof(p),strlen(q),strlen(p);\\結果是 4 3 3 2 char p[] = {'a','b','c','d','e','f','g','h'}; char q[] = {'a','b','c','d,'\0','e','f','g'}; sizeof(p); //結果是8 ===》p表示在內存中的大小 8×1 strlen(p); //爲一個隨機值,結果與編譯器有關,不同編譯器結果一般不同 sizeof(q); //結果是8 ===》p表示在內存中的大小 8×1 strlen(q); //結果爲4 ===》存在'\0',遇到'\0'計算停止。
struct Stu { int i; int j; char k; }; Stu stu; printf("%d\n",sizeof(Stu)); //結果 12 ===》內存補齊 printf("%d\n",sizeof(stu));; //結果 12 ===》內存補齊
- template
聲明一個模板,模板函數,模板類等。模板的特化。
- virtual
聲明虛基類,虛函數。虛函數=0時,則爲純虛函數,純虛函數所在的類稱爲抽象類。 爲了就是實現多態。
- typedef
- this
- typename
告訴編譯器把一個特殊的名字解釋爲一個類型。
- using
- void
- *_cast(四種類型轉換)
即 const_cast、dynamic_cast、reinterpret_cast、static_cast。
- C++類型風格來性轉換。const_cast刪除const變量的屬性,方便賦值;
- dynamic_cast用於將一個父類對象的指針轉換爲子類對象的指針或引用;
- reinterpret_cast將一種類型轉換爲另一種不同的類型;
- static_cast用於靜態轉換,任何轉換都可以用它,但他不能用於兩個不相關的類型轉換。