天天看點

C++核心知識點整理——基礎知識

尊重函數接口,盡量不作内部改動

C++代碼語句分為:内置類型,名字,變量,操作符,标量,字元串,預處理訓示(如#include)等

C++中定義類來組織資料結構

标準庫的頭檔案用尖括号 < > 括起來,非标準庫的頭檔案用雙引号 ” ” 括起來。

對象是記憶體中具有類型的區域。

在C++中,初始化和指派是兩種不同的操作。

内置類型變量在任何函數外如不初始化,系統都會初始化為0,在函數體内如不初始化則可能發生錯誤(除了用作左操作數)。

有些類類型有預設構造函數,是以定義其對象時可以不顯式地提供初始化。

在 C++ 語言中,變量必須且僅能定義一次,而且在使用變量之前必須定義或聲明變量,聲明變量不配置設定記憶體,是以聲名不初始化,若聲明同時初始化則視為定義。

extern關鍵字用于聲明。全局域定義的非 const 變量預設為 extern。要使 const 變量能夠在其他的檔案中通路,必須地指定它為 extern。

要了解的重要概念是引用隻是對象的另一名字,初始化是指明引用指向哪個對象的唯一方法。如int val = 1024;int &refval = val; //refval是val的引用,當int I = refval;相當于int I = val;引用是一種複合類型。

enum是枚舉關鍵字enum Points{point2d,point2w,point3d,point3w};表示花括号内成員預設為0,1,2,3都是const變量,用來初始化枚舉成員的值必須是一個常量表達式,但枚舉類型的對象的初始化或指派,隻能通過其枚舉成員或同一枚舉類型的其他對象來進行。Points是一個枚舉類型。

C++ 中,通過定義類來自定義資料類型。類定義了該類型的對象包含的資料和該類型的對象可以執行的操作。接口(interface)和實作(implement)。

定義變量和定義資料成員存在非常重要的差別,類中定義的變量稱為資料成員,當定義資料成員時,隻能指定該資料成員的名字和類型。類不是在類定義裡定義資料成員時初始化資料成員,而是通過稱為構造函數的特殊成員函數控制初始化。

C++中也可以使用struct關鍵字來定義類,它與class的差別在于類中第一個通路标号前的成員預設為public,而class預設為private。注意private隻是對于類外語句調用權限而言,在類内部成員函數可以随意調用private成員。

頭檔案用于聲明而不是定義,因為定義隻可以出現一次,而頭檔案在多個源檔案中出現,是以隻用于聲明。對于頭檔案不應該含有定義這一規則,有三個例外。頭檔案可以定義類、值在編譯時就已知道的 const 對象和 inline 函數。頭檔案中含有支援分别編譯所需的類定義及變量和函數的聲明。

C++預處理器是在編譯之前運作帶有預處理标志#的程式,如#include訓示允許兩種形式<>和“”,前者表示标準庫頭檔案,後者表示自定義頭檔案。#define預處理器變量,通常全部大寫字母。可以用:

#ifndef SALESITEM_H
#define SALESITEM_H
// Definition of Sales_itemclass and related functions goes here
#endif
           

首先第一句判斷SALESITEM_H是否定義,若沒有則第二句定義該預處理器變量,直到#endif結束。若第一句判斷出SALESITEM_H已經定義,則忽略後面的内容。此預處理指令可以用于避免頭檔案在被程式多次包含時内部定義的類被反複定義,引起編譯錯誤。

String類型的輸入操作符<<:忽略開頭的空白符(空格,制表符,換行符等),讀到該字元串第一次出現空白符終止。字元串字面值包含一個額外的空字元用于結束字元串,是以“string”包含7個字元。

先初略地了解一下vector和iterator的概念,以後用到時深入學習,vector容器是一種類型,vector ivec表示儲存int對象的類模闆。Iterator也是一個類,vector::iterator iter;表示由vector定義的疊代器類型對象iter,用于周遊容器中的元素。使用它們之前必須在檔案頭包含并using聲明。

C++ primer第三章介紹了幾個常用的标準庫類:vector,string,iterator和bitset。

C++ 語言提供了兩種類似于 vector 和疊代器類型的低級複合類型——數組和指針。現代 C++ 程式應盡量使用 vector 和疊代器類型,而避免使用低級的數組和指針。設計良好的程式隻有在強調速度時才在類實作的内部使用數組和指針。

數組定義的類型名可以是任意内置資料類型或類類型,數組元素可以是除了引用之外的任意複合類型。數組的維數必須用值大于等于1的常量表達式定義。此常量表達式隻能包含整型字面值常量、枚舉常量或者用常量表達式初始化的整型 const 對象。非 const 變量以及要到運作階段才知道其值的 const 變量都不能用于定義數組的維數。

與vector不同,數組不允許用另一個數組指派和初始化,數組一經定義就不允許再添加新元素。

指針的定義:int *p;從右往左讀,定義p為一個指向int類型對象的指針變量。一個有效的指針必然是以下三種狀态之一:儲存一個對象的位址;指向某個對象後面的另一個對象;0值。避免使用未初始化的指針。

指針的算術操作:加減整型數值。與疊代器的算術操作實作方式相同。對指針解引用,可得到它所指向的對象的值:*p。在表達式中使用數組名時,實際上是使用了指向該數組第一個元素的指針,注意數組名與指針變量的等價性。

C++ 允許計算數組或對象的超出末端的位址,但不允許對此位址進行解引用操作。如:

const size_t  arr_size = ;
int arr[arr_size] = {,,,,};
int *p = arr;
int *p2 = p + arr_size;
           

p2儲存的是數組arr_size超出末尾的位址。

指向const的指針了解為:“自以為指向const的指針”,當一個指針定義時指向const對象,它就會認為自己是一直指向const對象的指針,即使它後來指向一個非const對象,也不能通過引用修改該對象的值。但可以通過重新定義一個指向該對象的指針修改值。在實際的程式中,指向 const 的指針常用作函數的形參。

另外還有const指針,如int *const p = &val;const指針若指向const對象,則限制一切改動的行為。

位操作符<<和>>分别代表二進制數各位整體左移或右移右操作數位數。如int 12>>1;表示1100變為0110(6)。

指派操作傳回左值,具有右結合性。

j = i++與j = ++i的差別,前者自增操作符傳回初值,後者傳回自增後的值。盡量使用前置自增。

C++語言為包含點操作符和解引用操作符的表達式提供了一個同義詞:->箭頭操作符。

如:sales_item *sp = &item1; (*sp).same_isbn(item2);等效于sp->same_isbn(item2);

運用new和delete語句建立和撤銷動态記憶體,即可建立和釋放動态數組也可建立和釋放單個對象,如:int *pi = new int; 表示在自由存儲區(堆)配置設定了一個整型對象,并傳回該對象的位址,并用該位址初始化指針pi。

又如:int *pi = new int(20); 同時初始化該整型對象為20。string *ps = new string; string的預設構造函數将其初始化為一個空字元串。若要顯式初始化非預設初始化的對象,可寫為:

int *pi = new int();在類型名後面加圓括号表示初始化為空值,這樣做可以避免因未初始化帶來的錯誤。

delete pi; 表示釋放pi所指向記憶體,但pi中儲存的位址仍存在,此時pi成為懸垂指針,易發生錯誤,應立即将pi置0,以顯示它未指向任何對象。使用delete删除非自由存儲區的記憶體是不合法的。

對于const對象,須傳回const對象位址,如:const int *pi = new const int(1024);

C風格字元串是一個const char型字元數組:const char *ps = “C style”; 以空字元為結束位;C++标準庫用string類型重新定義了字元串,更加簡單直覺: string ps(“characters string”);

盡量使用string類來定義字元串。

C++編譯器在隐式類型轉換時會盡可能防止精度損失。強制類型轉換的一般格式為:

cast-name(expression) ; 其中cast-name是要強制轉換的方式,如static_cast;

const_cast 等,type是欲轉換為的類型。盡量避免使用強制類型轉換。

switch語句每個case後要加break,否則程式隻會跳過後續的case标号繼續執行case标号内的内容。若要在case中定義變量,則使用花括号限定變量的使用範圍。

C++異常處理關鍵字:throw和try{}catch{}catch{}…;了解一下,throw用于退出代碼塊,轉向異常處理。try一段代碼,catch其中的語句,作相應處理。标準庫定義的異常處理類都在stdexcept頭檔案中。

函數形參使用引用修改實參的值安全而友善,盡量不使用指針。

函數中如不需要修改實參的值,則統一使用const形參引用,如:下列程式在s中查找c字元:

string::size_type  find_char(string &s,char c){
  string::size_type i = ;
  while(i != s.size() && s(i) != c )
++i;
  return i;
}
           

若調用此函數find_char(“string”,’s’); 則出現編譯錯誤,字元串和字元字面值是右值,可以通過const string &s 引用,此處字面值常量先隐式轉化為一個臨時const對象再初始化const string &s。

區分int *matrix[10 ]; 和int (*matrix) [10];前者表示包含10個指針的指針數組,後者表示指向含有10個int型元素的數組的指針。 數組下标優先級大于指針操作符。

int main(int argc, char *argv[]) 中,argv是一個c風格的字元串數組,char *argv[]相當于char **argv,argc儲存argv的字元串個數。

左值可出現在指派語句的右側或左側,而右值隻能出現在指派号的右側。函數傳回值用于初始化在調用函數處建立的臨時對象。是以,函數可傳回引用作為左值:const string &shorterString(const string &s1,const string &s2),形參和傳回類型都是引用。但不要傳回局部對象的引用,同樣,可以傳回指針,但不能傳回局部對象的指針,否則會成為懸垂指針。

遞歸函數是直接或間接調用自身的函數,必須要有中止條件,否則會無限循環。如:定義一個遞歸函數求取1×2×3……100的值:

int f(int val){
  if (val > )  return f (val-)*val;
  return val;
}
           

函數聲明可省略形參名,一般在聲明階段提供預設實參:string screenInit(string::size_type width = 80, string::size_type height = 20, char background = ‘c’); 當調用函數時,初始化值會從左向右覆寫預設實參值,是以應将最有可能變更的預設實參放在最左邊。函數聲明一般整理放在頭檔案中,在源檔案中包含頭檔案。

函數中,每個名字都有作用域,每個對象都有生命期,形參和局部變量的生命期在函數調用過程中,它們的名字作用域限于函數塊中從定義到快結束之間。若我們希望一個局部對象在函數調用結束後仍然具有生命,則可以定義靜态局部變量:static關鍵字。

定義inline内聯函數是為了編譯器在處理函數時按照函數塊内語句展開,節省直接處理函數帶來的花銷。在普通函數前加inline關鍵字,并隻能在頭檔案中定義。

類的成員函數在類内聲明,可以在類外定義,也可以在類内定義。其形參表包含一個隐式形參this指針,初始化為調用該成員函數的對象位址,如:在Sales_item類中定義的成員函數:

bool same_isbn(const Sales_item &rhs) const {
  return isbn == rhs.isbn;
}
           

在調用total.same_isbn(trans)時,花括号前的const表明隐式指針this是一個指向total對象的const Sales_item* 類型的指針,該函數稱為常量成員函數。return isbn == rhs.isbn相當于:

return this->isbn == rhs.isbn; 函數體中可以顯式地使用後者語句,但沒有必要。

構造函數是一種特殊的成員函數,用于初始化類,同名構造函數可以重載,由不同數目或類型的形參表區分。構造函數沒有傳回類型,和類同名。

通常,我們将類放在與類同名的頭檔案中定義,而成員函數放在與類同名的源檔案中定義。

每個版本的重載函數應在同一個作用域中聲明,局部同名函數會覆寫全局函數而不是重載。

繼續閱讀