面向對象設計主要特徵是程序=對象+消息,對象是基本元素,對象接收到消息後,啓動有關方法完成操做。ios
面向對象程序設計的基本特徵有:抽象、封裝、繼承和多態。c++
c++支持編譯時的多態和運行時的多態,編譯時的多態經過函數重載實現,運行時的多態經過虛函數實現。數組
c++經過對c進行擴充,是面向過程程序設計和麪向對象設計的混合型程序設計語言。函數
c++程序通常由類的聲明和類的使用兩大部分組成。this
c++對c的擴充:spa
l c++除了保留c的進行輸入/輸出操做時常使用的printf()和scanf()函數外,新增標準輸入流對象cin和標準輸出對象cout。cin遇到空格,就認爲本數據輸入結束並檢查輸入數據與變量的匹配狀況。c++增長了操縱符對輸出數據格式進行控制,如換行操縱符endl。設計
l 在c語言中全局變量必須聲明在任何函數以前,局部變量必須集中在可執行語句以前,而c++容許變量聲明可與可執行語句交替出現。指針
l 在c++中,結構名、聯合名、枚舉名都是類型名。能夠像定義對象那樣,定義結構體、聯合體、枚舉。沒必要在前面冠以struct、union、enum。對象
l c語言建議爲每個函數創建函數原型,c++必須創建函數原型,以便在編譯時進行類型檢查。繼承
l c語言經常使用#define 來定義常量,可是容易出錯,c++推薦用const修飾符。
l 內聯函數以空間換時間的方式下降函數調用時的系統開銷,但要求內聯函數體內不含有負雜的控制語句,也不能過長,省得程序編譯後體量過大。c++中一個函數在類體內則被隱式的指定爲內聯函數,也能夠用inline顯式的指定內聯函數。
l 能夠定義帶有默認參數的函數。
l 用戶能夠重載函數,即在同一做用域中,能夠定義函數名相同的函數,只要函數參數類型不一樣或者參數個數不一樣或者兼而有之。
l 做用域標識符::c語言中函數內若有和全局變量同名的局部變量,則全局變量會被屏蔽沒法訪問,而c++中能夠在變量名前面使用::代表是使用全局變量。
l 計算機內存會被分爲四個區:程序代碼區、全程數據區、棧、堆。只有堆可由用戶分配和釋放。c語言中使用函數malloc函數和free來動態管理內存,c++提供了運算符new、delete來作一樣的工做。
l 引用,c++中引用就是變量的別名,故又稱別名。引用和原變量名指向內存中的同一區域。
l 傳遞函數參數的三種狀況,一、將變量名做爲函數參數,這是「傳值調用」,是單向傳遞,在函數運行過程當中,形參的變化不會傳遞給實參,二、指針變量做爲函數參數,這是「傳址調用」,是雙向傳遞,三、引用做爲函數參數,也是「傳址調用」雙向傳遞。
l 一般一個函數不能直接用在賦值運算符的左邊,例如
index(2)=25;這是不容許的,可是使用引用返回函數值就能夠這麼寫了:
int& index(int i)
{
return a[i];
}
index(2)=25;這是容許的,至關於a[2]=25;要注意的是引用不是一種數據類型,因此不能定義引用的引用、引用的指針、引用的數組。
類的構成:類和結構體的擴種形式十分類似,類生命中包括數據和函數,分別稱爲數據成員和成員函數,數據成員和成員函數有公有、保護、私有三種訪問權限。通常狀況下,類體中只給出成員函數原型,而函數體的定義放在類外。須要注意的是不能在類聲明中給數據成員賦初值。
相同類型的對象能夠相互賦值,如a=b,對象之間的賦值,僅僅是對數據成員的賦值,不一樣的對象的數據成員佔據不一樣的存儲空間而不一樣對象的成員函數是佔有同一個函數代碼段,沒法對他們賦值。當類體中存在指針時,使用賦值運算符進行賦值,可能會產生問題,即所謂的「淺拷貝」和「深拷貝」問題,淺拷貝時,由於含有指針,兩個對象指針指向同一塊內存區域,同一個對象調用析構函數時,該塊內存被釋放,當另外一個也調用析構函數,一樣要釋放該塊內存,而同一塊內存不能被釋放兩次,這時便會出現問題,要解決該類問題,就須要使用「深拷貝」。
構造函數是特殊的成員函數,其函數名必須和類名相同,能夠有任意的參數但不能有返回值甚至void也不行,它不須要用戶調用,在定義對象時自動執行且只執行一次,爲對象分配空間,進行初始化。
c++提供了除賦值運算符以外的初始化數據成員的方法,即成員初始化列表。對於用const修飾的數據成員,或是引用類型的數據成員,是不容許用賦值語句直接賦值的,只能用成員初始化列表進行初始化。
析構函數是另外一種特殊成員函數,一般用於撤銷對象時的一些清理工做,如釋放分配給對象的內存空間等。析構函數和構造函數名字相同,但在前面加一個波浪號(~),析構函數沒有參數也沒有返回值,並且不能重載。所以一個類中只有一個析構函數。當撤銷對象時,編譯系統會自動調用析構函數。
拷貝構造函數,它的做用是在創建一個新對象時,使用一個已經存在的對象去初始化這個新對象,如point p1(p2)或point p1=p2;拷貝構造函數只有一個參數,而且是同類對象的引用,每一個類都必須有一個拷貝構造函數。
由於成員函數代碼是同類全部對象共用,爲了使成員函數辨別出當前調用本身的是哪一個對象,c++引入了自引用指針this,每當建立一個對象,系統就把this指針指向該對象,當調用成員函數時,系統把this指針做爲一個隱含參數傳遞給該函數。
對象中的數據成員有本身獨立的存儲空間,互不相干,但有時但願不一樣的對象能夠共享一個或幾個數據成員,實現同類的不一樣對象間數據共享,因而有了靜態成員的概念。不管創建多少類的對象,都只有一份靜態數據成員的拷貝,從而實現同類的不一樣對象間的數據共享,靜態成員屬於類,因此能夠用類直接訪問。靜態成員函數不是爲了對象間的溝通,而是爲了處理靜態數據成員。靜態成員函數沒有this指針,因此通常不訪問非靜態成員,若是要訪問非靜態成員,則需顯式的經過對象名.非靜態成員名來訪問。
有了靜態成員來實現同類不一樣對象間的數據共享,一樣爲了實現類間的數據共享,c++引入了友元這一律念。友元是一扇通向私有成員的後門。
一個類的友元函數不是該類的成員,它能夠是不屬於任何類的非成員函數,也能夠是另外一個類的成員函數。定義時需在友元函數前添加關鍵字friend。一個類的友元函數能夠訪問該類的私有成員,但它畢竟不是該類成員,因此在定義和調用該類時沒必要像成員函數那樣在函數名前加上「類名::」。它也沒有this指針,須要顯式的經過「對象名.數據成員」才能訪問數據成員。成員函數只能訪問它所屬的類,但一個函數若是被定義爲多個類的友元函數,那它能夠訪問這些類的全部數據。使用友元函數時必需要慎重。
能夠將一個類好比y定義爲另外一個類x的友元類,那麼y類中的全部成員函數都是x類的友元函數。
繼承就是從先輩處獲得屬性和行爲特徵,較好的解決了代碼重用的問題。默認爲私有繼承,還有公有繼承、保護繼承。基類的構造函數和析構函數不能被繼承,當建立派生類對象時,先調用基類的構造函數,在調用派生類的構造函數,撤銷派生類的對象時,順序相反。在沒有虛函數的狀況下,若是派生類中定義了與基類成員同名的成員,稱派生類成員覆蓋了基類成員,如要在派生類中使用基類同名成員,必須使用「基類名::同名成員」的方式顯式指定,若是在對象中調用就用「對象名.基類名::同名成員」。
當一個派生類有多個基類時,成爲多繼承。多繼承要注意構造函數的書寫,同時多繼承帶來一個問題:當派生類y有兩個基類a和b,同時a和b有一個共同的基類c,這樣y就會繼承兩個c的拷貝,當要訪問c的成員時,必須顯式的指定是a仍是b的成員,以避免產生二義性,爲了解決這個問題,c++引入虛基類的概念。上例中能夠把c聲明爲a和b的虛基類,即:class a:virtual 繼承方式 c和class b:virtual 繼承方式 c這樣從a和b繼承的y只會繼承c一次。
不一樣數據類型數據之間的自動轉換和賦值,稱爲賦值兼容。基類和派生類對象之間也存有賦值兼容關係:在基類對象可使用的地方均可以用派生類的對象來替代。派生類對象能夠賦值給基類對象,指向基類對象的指針能夠指向基類的公有派生類,但不能指向私有派生類。
所謂多態性就是不一樣對象收到相同的消息,產生不一樣的動做。連編是把函數名和函數體的程序代碼鏈接(聯繫)在一塊兒的過程。靜態連編在編譯階段就完成了,函數調用速度快,效率高,但缺少靈活性,動態連編在運行階段完成,在程序運行時纔去肯定調用哪一個函數,下降了程序運行效率但加強了靈活性。c++是編譯型語言,仍採用靜態連編,好在c++引入了「虛函數」從而實現了靜態連編和動態連編相結合。虛函數是基類中的成員函數,前面加有關鍵字virtual,並在派生類中被重載,在派生類中被從新定義時其函數原型包括返回類型、函數名、參數個數、參數類型的順序,都必須和基類中的原型徹底相同。
虛函數使用的基礎是賦值兼容規則,而賦值兼容規則成立的前提條件是派生類從其基類公有派生,因此要想經過定義虛函數來實現動態多態性派生類就必須是從基類公有派生。內聯函數不能是虛函數,由於內聯函數不能在運行中動態肯定其位置,因此即便虛函數在類的內部定義。編譯時仍將它當作非內聯的。
基類每每表示一種抽象的概念,此時在基類中預留一個函數名,具體功能留給派生類根據須要去定義,這樣一個虛函數就成爲純虛函數,格式以下:virtual 返回類型 函數名(參數表)=0;含有純虛函數的類稱爲抽象類。抽象類的目的就是用它去創建派生類,抽象類不能實例化爲對象。也不容許從非抽象類派生出抽象類,抽象類也不能作函數參數類型、返回類型或顯式轉換的類型。
運算符的重載,須要寫一個運算符函數,好比要重載」+」號,就要寫一個名爲operator+的函數。運算符重載函數有兩種形式,一種是定義爲它要操做的類的成員函數,另外一種是定義爲該類的友元函數。友元運算符重載函數以下:
class x{
……
friend 返回類型 operator運算符(形參表);
……
}
注意友元函數不是類x的成員不能直接訪問x的成員,要顯式指定「x.成員名」也沒有this指針。並非全部的運算符均可以定義爲友元運算符重載函數,如賦值運算符「=」,下標運算符「[]」,函數調用運算符「()」等。
對於x=x1+x2;c++解釋爲x=operator+(x1,x2);
成員運算符重載函數格式以下:
class x{
……
返回類型 operator運算符(形參表);
……
}
由於成員函數能夠在函數體內直接訪問類x的成員,並且有this指針隱含的指向當前對象,因此對於雙目運算符,只需一個形參就能夠了。
對於x=x1+x2;c++解釋爲x=x1.operator+(x2);
通常來講,雙目運算符能夠被重載爲友元函數活成員函數,但也有例外只能用友元函數,好比一個類的對象和一個整數或其餘類對象相加的成員函數:
若是是x和整數i相加 x=x1+i;是正確的,由於c++解釋爲x=x1.operator+(i);
但x=i+x1;卻出錯,由於c++解釋爲x=i.operator+(x1);可是i是整數,並無成員函數operator+因此編譯出錯。
爲了解決這一問題,只能定義兩個友元函數:
class x{
……
friend 返回類型 operator運算符(x& x1,int i);
friend 返回類型 operator運算符(int i, x& x1);
……
}
利用函數重載來解決運算符兩邊操做數交換的問題。
對於「++」和「--」等分前綴用法後綴用法的運算符用「int」區分,沒有int是前綴用法,有是後綴用法。
class x{
……
friend 返回類型 operator運算符(x& x1);//前綴
friend 返回類型 operator運算符( x& x1,int);//後綴
……
}
爲了解決「淺拷貝」帶來的「指針懸掛」問題,能夠重載賦值運算符」=」,引入深拷貝。
類型轉換分爲標準類型(如int,float,double,char等)間的轉換和類類型和標準類型間的轉換。準類型間的轉換c++已經自帶了方法轉換,不需用戶在寫方法。
類類型和標準類型間的轉換有兩種方法一、經過轉換構造函數進行類型轉換二、經過類型轉換函數進行類型轉換。
在程序設計的過程當中常常出現這樣的狀況:兩個或多個函數的函數體徹底相同,差異僅在於它們的參數類型不一樣,爲了提升代碼的可重用性和可維護性,c++提出了模板概念。
在c語言中能夠用宏定義#define,可是宏定義避開了類型檢查,容易出錯。
模板能夠實現參數類型參數化,即把數據類型定義爲參數,從而實現代碼重用。模板分爲函數模板和類模板,他們分別用來創建模板函數和模板類。
函數模板是創建一個通用函數,其函數返回類型和參數類型不具體指定,用一個虛擬的類型來表明,這個通用函數就是函數模板,系統調用函數時根據實參的類型取代模板中虛擬類型。
格式以下:
template <typename 類型參數>
返回類型 函數名(模板形參表)
{
函數體
}
或者
template <class 類型參數>
返回類型 函數名(模板形參表)
{
函數體
}
通常爲了與類聲明中的class區分,通常用第一種格式,c++中的類型參數通常是t、type等。,typename和class用來表名後面的參數是一個虛擬的類型名。函數模板須要實例化一個模板函數才能調用,當編譯系統發現一個函數調用
函數名(模板實參表)
就會根據模板實參表中的類型生成一個函數即模板函數。模板函數中的函數體與函數模板函數體相同。函數模板能夠和同名的非模板函數重載,調用順序是先尋找一個參數徹底匹配的非模板函數,若是有就調用沒有就尋找函數模板將其實例化,如實例化模板函數成功就調用它。
對於類的聲明也能夠採用相似的方法,使用類模板能夠簡化那些功能相同而數據類型不一樣的類的聲明。格式以下:
template <typename 類型參數>
class 類名{
類成員聲明
};
或
template <class 類型參數>
class 類名{
類成員聲明
};
類模板定義對象的格式是:
類名<數據實際類型> 對象名(參數表);
c++支持c語言的輸入輸出系統以外,還定義了一套面向對象的輸入輸出系統。「流」是數據從一個源留到目的的抽象,負責數據的生產者和消費者之間創建聯繫並管理數據的流動。i/o流類庫中各類類的聲明包含在相應的頭文件中如iostream、fstream、strstream、iomanip。
類ios是流的基類是抽象類。流類定義的對象稱爲流對象,c++中有幾個預約義好的流對象:標準輸入流對象cin、標準輸出流對象cout、非緩衝型標準出錯流對象cerr和緩衝型標準出錯流對象clog。
cout中經常使用的成員函數:cout.put(a)輸出一個字符a;
cin中經常使用的成員函數:cin.get(ch)功能是從輸入流讀取一個字符(包括空白符)賦給字符型變量ch;cin.getline(字符數組,字符個數n,終止標識符)或cin.getline(字符指針,字符個數n,終止標識符)功能是從輸入流讀取n-1個字符,若是提早讀到終止標識符就提早結束最後總要插入一個字符串結束標誌’\n’。cin.ignore(n,終止字符)功能是跳過輸入流中的n個(默認1個)字符或遇到指定的終止字符(默認是eof)提早結束跳躍。
流基類ios中定義了一些進行輸入輸出格式控制的成員函數,查看書籍,除此以外c++提供了另外一種輸入輸出格式控制的方法,稱爲操縱符,查閱書籍,用戶也能夠自定義操縱符。格式以下:
輸出流:
ostream &操縱符名 (ostream &stream)
{
自定義代碼
return stream;
}
輸入流:
istream &操縱符名 (istream &stream)
{
自定義代碼
return stream;
}
文件流用來處理外存文件,根據文件中數據的組織形式,文件可分爲兩類:文本文件和二進制文件。文本文件又稱ASCii文件,一個字節存放一個ASCII代碼表明一個字符,二進制文件則是內存中的存儲形式原樣寫到外存中造成的文件,好比整數100,在文本文件中是以‘1’、‘0’、‘0’三個字符的ASCII的代碼存放的,佔3個字節,而在二進制文件中就是100的二進制形式01100100存放的,佔一個字節。
C++進行文件操做的通常步驟:一、爲要進行操做的文件創建一個文件流對象,二、打開文件,若是不存在就建立該文件,三、進行讀寫操做,四、關閉文件。用到的類ifsteam(用於文件輸入)、ofsteam(文件輸出)、fsteam(文件輸入輸出)。
成員函數:
文件流對象.open(文件名,使用方式):以特定方式打開文件
文件流對象.open():關閉文件
文件流對象<<數據:寫入文件
文件流對象>>變量:讀取數據
文件流對象.read(char *buf,int len):讀取len個字符到buf數組
文件流對象.write(const char *buf,int len):將buf數組中len個字符寫入文件。
文件流對象.eof():檢測是否到達文件尾。
隨機讀寫函數:看書籍。
命名空間是由程序設計者命名的一個內存區域,用來處理程序中同名衝突問題。定義格式以下:
Namespace 空間名
{
代碼
}
C語言中沒有命名空間,若是C++使用的帶擴展名.h的頭文件,沒必要使用命名空間。若是C++使用的不帶擴展名.h的頭文件就要指定頭文件所在的命名空間。
程序中的常見錯誤分爲:編譯時的錯誤和運行時的錯誤。編譯時的錯誤主要是語法錯誤,運行過程的錯誤統稱爲異常,對異常的處理就是異常處理。
C++中處理異常的辦法是:若是執行一個函數出現異常,能夠不在本函數處理而是甩給上一級也就是函數的調用者,一直能夠逐級上傳一直到最高級,若是最高級也沒法處理,系統會調用系統函數terminate(),有它調用abort終止程序。
C++異常處理機制有檢查、拋出和捕獲三個部分:try(檢查)、catch(捕獲)、throw(拋出)
格式以下:
Throw 表達式:
Int i;
Throw i;由於i是整型變量,因此throw拋出的是整型異常;
Throw拋出的異常會由catch捕獲。
Try
{
被檢查的語句
}
Catch(異常類型聲明1)
{
進行異常處理的語句1
}
Catch(異常類型聲明2)
{
進行異常處理的語句2
}
……
Try和catch必須配套使用。
本書主要內容就是這些。