最近決定把Lippman的大作《C++ Primer》重新溫習一遍,在查閱的過程中記錄下一些重要的知識點,希望對於自己有一定的協助。為方便查詢,全部內容按照章節分類。
第一章 快速入門
1、iostream庫的基礎是兩種命名為istream何ostream的類型,分別表示輸入資料流和輸出資料流。
標準庫定義了4個IO對象,處理輸入時使用cin的istream類型對象。處理輸出時使用命名為cout的ostream類型對象。處理標準錯誤的用來輸出警告和錯誤資訊給程式的cerr對象。用於產生程式執行的一般資訊的clog對象。
2、讀入未知數目的輸入:利用while語句判斷,直到遇到檔案結束符(ctrl+z)
while(std::cin>>value)<br /> sum+=value;
第二章 變數和基本類型
1、複製初始化和直接初始化
int ival(1024);//直接初始化<br />int ival=1024;//複製初始化
2、初始化不是賦值:初始化是指建立變數並給它賦初始值,而賦值則是擦除對象的當前值並用新值代替。
3、聲明和定義:變數的定義用於為變數分配儲存空間,還可以為變數指定初始值,在一個程式中,變數有且僅有一個定義;聲明用於向程式表明變數的類型和名字,定義也是聲明:當定義變數時我們聲明了它的類型和名字。可以通過extern關鍵字聲明變數名而不定義它。
extern int i;//聲明但沒有定義<br />int i;//聲明並且定義i
4、常量在定義時必須初始化:因為常量在定義後就不能被修改,所以必須初始化。
const string hi="Hello";//True:初始化<br />const int i;//Error:i is uninitialized const
5、const引用:const引用時執行const對象的引用
const int ival=1024;<br />const int &refival=ival;//OK:both reference and object are const<br />int &refival2=ivale;//error:nonconst reference to a const object
6、用class和struct關鍵字定義類的唯一差別在於預設存取層級:預設情況下struct的成員為public.而class成員為private.
第三章 標準庫類型
除了基本的資料類型外,C++還定義了一個內容豐富的抽象資料類型標準庫。其中最重要的標準庫類型就是string和vector,他們分別定義了大小可變的字串和集合。另外一種標準庫類型bitset提供了一種抽象方法來操作位的集合。本章主要介紹標準庫中的vector、string和bitset類型。
1、string類型對象的定義和初始化
#include<string><br />using std::string;</p><p>string s1;<br />string s2(s1);<br />string s3("value");<br />string s4(n,'c');
2、為了與C語言相容,字串字面值與標準庫string類型不是同一種類型,編程時一定要注意區分。 當進行string對象和字串字面值混合串連操作時,+操作符的左右操作符必須至少有一個是string類型的。
string s1="hello";<br />string s2="world";<br />string s3=s1+","; //OK<br />string s4="hello"+",";//Error<br />string s5=s1+s2;//OK<br />
3、#include<cctype.h>對string對象中單個字元進行處理。
4、標準庫vector類型
#include<vector><br />using std:vector;</p><p>vector<T> v1;<br />vector<T> v2(v1);<br />vector<T> v3(n,i);<br />vector<T> v4(n);</p><p>v.empty();//如果v為空白,則返回true<br />v.size();//返回v中元素的個數<br />v.push_back(t);//在v的末尾增加一個值為t的元素
5、僅能對確知已存在的元素進行下標操作:
vector<int> ivec;<br />cout<<ivec[0];//Error:ivec has no elements</p><p>vector<int> ivec2(10);<br />cout<<ivec2[10];//Error:ivec has elements 0...9
6、除了使用下標來訪問vector對象的元素外,標準庫還提供了另一種訪問元素的方法:使用迭代器,迭代器是一種檢查容器內元素並遍曆元素的資料類型。
vector<int>::iterator iter;
7、begin和end操作:
vector<int>::iterator iter=ivec.begin();//指向第一個元素<br />vector<int>::iterator iter=ivec.end();//由end操作返回的迭代器指向vector的"末端元素的下一個"
8、解引用操作符*與下標的區別
for(vector<int>::size_type ix=0;ix!=ivec.size();++ix)<br /> ivec[ix]=0;</p><p>for(vector<int>::iterator iter=ivec.begin();iter!=ivec.end();++iter)<br /> *iter=0;
9、每種容器類型還定義了一種名為const_iterator的類型,該類型只能用於讀取容器內元素,但不能改變其值。使用const_iterator類型時,我們可以得到一個迭代器,它自身的值可以改變,但不能用來改變所指向的元素的值。
for(vector<string>::const_iterator iter=text.begin();iter!=text.end();++iter)<br /> cout<<*iter<<endl;//print each element in text</p><p>for(vector<string>::const_iterator iter=text.begin();iter!=text.end();++iter)<br /> *iter=" ";//Error:*iter is const</p><p>
10、不要把const_iterator對象與const的iterator對象混淆起來,聲明一個const迭代器時,必須初始化迭代器。一旦被初始化後,就不能改變它的值。
vector<int> nums(10);//nums is nonconst<br />const vector<int>::iterator cit=nums.begin();<br />*cit=1;//OK:cit can change its underlying element<br />++cit;//Error:can't change the value of cit
11、string對象和bitset對象之間是反向轉化的:string對象的最右邊字元用來初始化bitset對象的低階位。當用string對象初始化bitset對象時,記住這一差別很重要。如果string對象的字元個數小於bitset類型的長度,則高階位置為0.
string strval("1100");<br />bitset<32> bitvec(strval);//bitvec的位元模式中第2和3的位置為1,其餘位置為0
第四章 數組和指標
C++語言提供了兩種類似於vector和迭代器類型的低級複合類型——數組和指標。現代C++程式應盡量使用vector和迭代器類型,而避免使用低級的數組和指標,設計良好的程式只有在強調速度時才在類實現的內部使用數組和指標。與vector類型相比,數組的顯著缺陷在於:數組的長度是固定的,而且程式員無法知道一個給定數組的長度,數組沒有擷取其容量大小的size操作,也不提供push_back操作在其中自動添加元素。如果需要更改數組的長度,程式員只能建立一個更大的新數組,然後把原數組的所有元素複製到新數組空間中。
1、數組的定義和初始化:數組的維數必須用值大於等於1的常量運算式定義,此常量運算式只能包含整型字面值常量、枚舉常量或者用常量運算式初始化的整型const對象。非const變數以及要到運行階段才知道其值的const變數都不能用於定義數組的維數。
const unsigned buf_size=512,max_files=20;<br />int staff_size=27;<br />const unsigned sz=get_size();</p><p>char input_buffer[buf_size];//ok,const variable<br />string fileTable[max_files+1];//ok,constant expression<br />double salaries[staff_size];//error:non const variable<br />int test_scores[get_size()];//error:要到運行時調用函數才知道值,non const expression<br />int vals[sz];//error:size not konwn until run time
2、不允許數組直接複製和賦值:與vector不同,一個數組不能用另外一個數組初始化,也不能將一個數組賦值給另一個數組。
int ia[]={0,1,2};<br />int ia2[](ia);//error:不能用另外一個數組初始化</p><p>const unsigned array_size=3;<br />int ia3[array_size];//ok,but elements are uninitialized<br />ia3=ia;//error:不能將一個數組賦值給另外一個數組
3、數組的長度是固定的:與vector不同,數組不提供push_back或者其他的操作在數組中添加新元素,數組一經定義,就不允許再添加新的元素。
4、vector的遍曆可使用下標或迭代器實現,同理,也可用下標或指標來遍曆數組,指標式指向某種類型對象的符合資料類型,是用於數組的迭代器,指向數組中的一個元素,在指向數組元素的指標上使用解引用操作符*和自增操作符++,與在迭代器上的用法類似。
string s("helloworld");<br />string *sp=&s;//定義了一個指向string類型的指標sp
5、理解指標聲明語句時,請從右向左閱讀
string *pstring;//把pstring定義為一個指向string類型對象的指標變數</p><p>double dp,*dp2;//該語句定義了一個double類型的dp對象以及一個指向double類型對象的指標dp2</p><p>string* ps;//把ps定義為一個指向string類型對象的指標</p><p>string* ps1,ps2;//ps1定義為指標,ps2並非指標,只是一個普通的string對象而已</p><p>string* ps1,*ps2;//定義兩個指標
6、指標初始化和賦值操作的約束,對指標進行初始化或賦值只能使用以下四種類型的值:(1) 0值常量運算式(2) 類型匹配的對象的地址(3) 另一對象之後的下一地址(4) 同類型的另一個有效指標。把int型變數賦給指標是非法的。
int ival;<br />int zero=0;<br />const int c_ival=0;<br />int *pi=ival;//error:pi initialized from int value of ival<br />pi=zero;//errro:pi assigned int value of zero<br />pi=c_ival;//ok:c_ival is a const with compile time value of 0<br />pi=0;//ok:directly initialize to literal constant 0
7、void*指標:它可以儲存任何類型對象的地址:void*表明該指標與一地址值相關,但不清楚儲存在此地址上的對象的類型,void*指標只支援幾種有限的操作:與另一個指標進行比較;向函數傳遞void*指標或從函數返回void*指標;給另一個void*指標賦值。不允許使用void*指標操作它所指向的對象。
double obj=3.14;<br />double *pd=&obj;<br />void *pv=&obj;<br />pv=pd;
8、指標提供間接操作其所指對象的功能,與對迭代器進行解引用操作一樣,對指標進行解引用可訪問它所指的對象。
string s("hello world");<br />string *sp=&s; //sp holds the address of s<br />cout<<*sp; //print hello world
9、指標和引用的比較,雖然使用引用和指標都可間接的訪問另一個值,但它們之間有兩個重要的區別:
第一個區別在於引用總是指向某個對象,定義引用時沒有初始化是錯誤的;第二個去背則是賦值行為的區別,給引用賦值修改的是該引用所關聯的對象的值,而並不是引用與另一個對象關聯。引用一經初始化,就始終指向同一個特定對象。
//賦值結束後,pi所指向的ival對象值保持不變<br />int ival=1024,ival2=2048;<br />int *pi=&ival,*pi2=&ival2;<br />pi=pi2;//pi now points to ival2</p><p>//這個賦值操作修改了ri引用的值ival對象,而並非引用本身<br />int &ri=ival,&ri2=ival2;<br />ri=ri2; //assigns ival2 to ival<br />
10、指向指標的指標:C++使用**操作符指派一個指標指向另一個指標,為了真正訪問到ival對象,必須對ppi進行兩次解引用。
int ival=1024;<br />int *pi=&ival;//pi points to an int<br />int **ppi=π//指向指標的指標</p><p>cout<<**ppi<<endl;//兩次解引用取得ival的值
11、指標和const限定符
(1) 指向const對象的指標:如下的cptr是一個指向double類型const對象的指標,const限定了cptr指標所指向的物件類型,而並非cptr本身。也就是說cptr本身並不是const,如果需要的話,允許給cptr重新賦值,使其指向另一個const對象,但不能通過cptr修改其所指對象的值。同時把const對象的地址賦給一個普通的、非const對象的指標也會導致編譯時間的錯誤,不能使用void*指標儲存const對象的地址
const double *cptr;//cptr may point to a double that is const</p><p>const double pi=3.1415;<br />double *ptr=π//error:ptr is a plain point<br />const double *cptr=π//ok<br />*cptr=42;//error:*cptr might be const</p><p>const int universe=42;<br />const void* cpv=&universe;//ok:cpv is const<br />void *pv=&universe;//error:不能使用void*指標儲存const對象的地址</p><p>double dval=3.14;<br />cptr=&dval;//允許把非const對象的地址賦給指向const對象的指標
(2) const指標:本身的值不能修改,如下curErr是指向int型對象的const指標,const指標的值不能修改,這就意味著不能使curErr指向其他對象,任何企圖給const指標賦值的行為,都會導致編譯時間的錯誤
int errNumb=0;<br />int *const curErr=&errNumb;//curErr為const指標</p><p>curErr=curErr;//異常:不能修改const指標的值
(3) 指向const對象的const指標:既不能修改pi_ptr所指向對象的值,也不允許修改該指標的指向。
const double pi=3.1415926;<br />const double *const pi_ptr=pi;//
12、指標和typedef,如下面代碼所示,cstr變數是什麼類型?
typedef string *pstring;<br />const pstring cstr;
一般說來cstr是const pstring類型的指標,那const pstring指標所表示的真實類型是什嗎?注意不是指向string類型的const對象(不能簡單的把typedef當做文本擴充),而是指向string類型對象的const指標,因為const修飾的是pstring的類型。
13、C風格字串:以Null 字元null結束的字元數組
char cal1[]={'C','+','+'};//不是C風格字串<br />char cal2[]={'C','+','+','/0'};//C風格字串<br />char cal3[]="C++";//自動添加null,為C風格字串
14、C風格字串的標準庫函數,必須包含相應的C標頭檔#include<cstring>
strlen(s);//返回s的長度,不包括字串結束符null<br />strcmp(s1,s2);//比較兩個字串s1和s2是否相同。<br />strcat(s1,s2);//將字串s2串連到s1後,並返回s1<br />strcpy(s1,s2);//將s2複製給s1,並返回s1<br />strncat(s1,s2,n);//將s2的前n個字元串連到s1後面,並返回s1<br />strncpy(s1,s2,n);//將s2的前n個字元複製給s1,並返回s1
15、動態定義數組以及初始化數組:可以使用跟在數組長度後面的一對空圓括弧對數組元素做值初始化。
int *pia=new int[10];//分配了一個含有10個int型元素的數組<br />int *pia2=new int[10]();//把數組元素都設定為0</p><p>const int *pci_bad=new const int[100];//Error:uninitialized const array<br />const int *pci_ok=new const int[100]();//OK:value-initialized const array
16、C語言使用一對標準庫函數malloc和free在自由儲存區配置儲存空間,而C++語言則使用new和delete運算式實現相同的功能。注意動態空間的釋放,在關鍵字delete和指標之間的空方括弧對必不可少。它告訴編譯器該指標指向的是自由儲存區中的數組,而並非單個對象。
delete [] pia;//該語句回收了pia所指的數組
17、string類提供了一個名為c_str的成員函數,用於返回C風格字串,即返回指向字元數組首地址的指標,該數組存放了與string對象相同的內容,並且以結束符null結束。
string str("Hello World");<br />char *str1=str;//Error<br />char *str2=str.c_str();//OK
第五章 運算式
本章重點介紹C++語言定義的操作符,他們使用內建類型的運算元。
1、sizeof操作符:返回一個對象或類型名的長度,返回的類型為size_t,長度的單位是位元組,具有以下三種文法形式:
sizeof(type name);<br />sizeof(expr);<br />sizeof expr;
2、強制轉換:dynamic_cast(支援運行時識別指標或引用所指向的對象)、const_cast(將轉換掉運算式的const性質)、static_cast(編譯器隱式進行的任何資料類型都可以由它顯式完成)、reinterpret_cast(通常為運算元的位元模式提供較低層次的重新解釋)