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 = 5;
int arr[arr_size] = {0,1,2,3,4};
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);

運用newdelete語句創建和撤銷動態內存,即可創建和釋放動態數組也可創建和釋放單個對象,如: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 = 0;
  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 > 1)  return f (val-1)*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; 函數體中可以顯式地使用後者語句,但沒有必要。
構造函數是一種特殊的成員函數,用於初始化類,同名構造函數可以重載,由不同數目或類型的形參表區分。構造函數沒有返回類型,和類同名。

通常,我們將類放在與類同名的頭文件中定義,而成員函數放在與類同名的源文件中定義。

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章