C++ 面向對象基本概念

 

/* 類和對象 */

 

 

 

1. 對象

客觀世界中任何一個事物都可以看成一個對象(object)。對象可大可小。
對象是構成系統的基本單位。
任 何 一 個 對 象 都 應 當 具 有 這 兩 個 要 素 , 即 屬 性 (attribute) 和 行 爲
(behavior),它能根據外界給的信息進行相應的操作。

 

 

2. 封裝與信息隱蔽

可以對一個對象進行封裝處理,把它的一部分屬性和功能對外界屏蔽,
也就是說從外界是看不到的,甚至是不可知的。這樣做的好處是大大降低了操
作對象的複雜程度。


封裝,指兩方面的含義:
一是將有關的數據和操作代碼封裝在一個對象中,形成一個基本單位,
各個對象之間相對獨立,互不干擾。
二是將對象中某些部分對外隱蔽,即隱蔽其內部細節,只留下少量接口,
以便與外界聯繫,接收外界的消息。這種對外界隱蔽的做法稱爲信息隱蔽

 

 

 

3.抽象

在程序設計方法中, 常用到抽象(abstraction)這一名詞。
 抽象的過程是將有關事物的共性歸納、集中的過程。抽象的作用是表示同一類事物的本質。


C和C++中的數據類型就是對一批具體的數的抽象。對象是具體存在的,
如一個三角形可以作爲一個對象, 10個不同尺寸的三角形是10個對象。如果
這10個三角形對象有相同的屬性和行爲,可以將它們抽象爲一種類型,稱爲三角形類型。


在C++中,這種類型就稱爲“類(class )”。這10個三角形就是屬於同一“類”
的對象。類是對象的抽象,而對象則是類的特例,或者說是類的具體表現形
式。

 

 

 

 

 

4. 繼承與重用

如果在軟件開發中已經建立了一個名爲A的“類”,又想另外建立一個名爲B的“類”,
而後者與前者內容基本相同,只是在前者的基礎上增加一些屬性和行爲,
只需在類A的基礎上增加一些新內容即可。這就是面向對象程序設計中的繼承機制。


利用繼承可以簡化程序設計的步驟。
“白馬”繼承了“馬”的基本特徵, 又增加了新的特徵(顏色), “馬”是父類,
或稱爲基類, “白馬”是從“馬”派生出來的,稱爲子類或派生類。

 

 

 

 

 

5.多態性

如果有幾個相似而不完全相同的對象,有時人們要求在向它們發出同一個消息時,
它們的反應各不相同, 分別執行不同的操作。這種情況就是多態現象。


如,在Windows環境下,用鼠標雙擊一個文件對象(這就是向對象傳送一個消息),
如果對象是一個可執行文件,則會執行此程序,如果對象是一個文本文件,則啓動文本編輯器並打開該文件。


在C++中, 所謂多態性(polymorphism)是指: 由繼承而產生的相關的不同的類,
其對象對同一消息會作出不同的響應。多態性是面向對象程序設計的一個重要特徵,能增加程序的靈活性。




基於對象和麪向對象程序設
計就是把一個算法和一組數據結構封裝在一個對象中。因此,就形成了新的
觀念:
對象 = 算法 + 數據結構
程序 = (對象+對象+對象+…) + 消息
或:
程序 = 對象s + 消息




class定義的類,如果不作private或public聲明,系統將其成員默認爲 private


每個對象所佔用的存儲空間只是該對象的數據部分所佔用的存儲空間
用一段空間來存放這個共同的函數代碼段

 

 

 

 

 

/*有關構造函數的使用,有以下說明:*/

(1) 在類對象進入其作用域時調用構造函數。
(2)構造函數沒有返回值,因此也不需要在定義構造函數時聲明類型,這
是它和一般函數的一個重要的不同之點。
(3) 構造函數不需用戶調用,也不能被用戶調用。
(4) 在構造函數的函數體中不僅可以對數據成員賦初值,而且可以包含
其他語句。
但是一般不提倡在構造函數中加入與初始化無關的內容,以保持程序的
清晰。
(5) 如果用戶自己沒有定義構造函數,則C++系統會自動生成一個構造函
數,只是這個構造函數的函數體是空的,也沒有參數,不執行初始化操作

 

 

 

 

 

/*~析構函數*/

①如果在一個函數中定義了一個對象(它是自動局部對象),當這個函數
被調用結束時,對象應該釋放,在對象釋放前自動執行析構函數。
②static局部對象在函數調用結束時對象並不釋放,因此也不調用析構函
數,只在main函數結束或調用exit函數結束程序時,才調用static局部對象的析
構函數。
③如果定義了一個全局對象, 則在程序的流程離開其作用域時(如main
函數結束或調用exit函數) 時,調用該全局對象的析構函數。
④如果用new運算符動態地建立了一個對象,當用delete運算符釋放該對
象時,先調用該對象的析構函數。




調用析構函數的次序正好與調用構造函數的次序相反 :
最先被調用的構造函數, 其對應的(同一對象中的)析構函數最後被調用,而最
後被調用的構造函數,其對應的析構函數最先被調用。






下面歸納一下什麼時候調用構造函數和析構函數 :


(1) 在全局範圍中定義的對象(即在所有函數之外定義的對象),它的構造
函數在文件中的所有函數(包括main函數)執行之前調用。
但如果一個程序中有多個文件,而不同的文件中都定義了全局對象,則
這些對象的構造函數的執行順序是不確定的。
當main函數執行完畢或調用exit函數時(此時程序終止),調用析構函數。(2) 如果定義的是局部自動對象(例如在函數中定義對象),則在建立對象
時調用其構造函數。
如果函數被多次調用,則在每次建立對象時都要調用構造函數。
在函數調用結束、對象釋放時先調用析構函數。
(3) 如果在函數中定義靜態(static )局部對象,則只在程序第一次調用此
函數建立對象時調用構造函數一次,在調用結束時對象並不釋放,因此也不
調用析構函數,只在main函數結束或調用exit函數結束程序時,才調用析構函數。

 

 

 

 

 

 

 

/*常對象。*/

定義常對象的一般形式爲
類名 const 對象名[(實參表列)];
也可以把const寫在最左面:
const 類名 對象名[(實參表列)];
二者等價。
如果一個對象被聲明爲常對象, 則不能調用該對象的非const型的成員函
數(除了由系統自動調用的隱式的構造函數和析構函數)。


引用常對象中的數據成員很簡單,只需將該成員函數聲明爲const即可。如 :
void get_time( ) const ; //將函數聲明爲const


指向對象的常指針
Time * const ptr1=&t1; //指定ptr1指向t1


指向常對象的指針變量
ptr: const char *ptr;


(1) 如果一個變量已被聲明爲常變量,只能用指向常變量的指針變量指
向它, 而不能用一般的(指向非const型變量的)指針變量去指向它。
(2) 指向常變量的指針變量除了可以指向常變量外,還可以指向未被聲
明爲const的變量。
此時不能通過此指針變量改變該變量的值。
如果希望在任何情況下都不能改變c1的值,則應把它定義爲const型。
(3) 如果函數的形參是指向非const型變量的指針,實參只能用指向非
const變量的指針,而不能用指向const變量的指針,這樣,在執行函數的過程
中可以改變形參指針變量所指向的變量(也就是實參指針所指向的變量)的值。

 

 

 

 

 

/* 類的繼承 */

類的繼承是用已有的類來建立專用類的編程技術。


一個派生類不僅可以從一個基類派生,也可以從多個基類派生。
一個派生類有兩個或多個基類的稱爲多重繼承(multiple inheritance)


基類和派生類的關係,可以表述爲:派生類是基類的具體化,而基類
則是派生類的抽象。


class 派生類名: [繼承方式] 基類名{派生類新增加的成員};
繼承方式包括: public (公用的),private (私有的)和protected(受保護的)




構造一個派生類包括以下3部分工作:
(1) 從基類接收成員。
(2) 調整從基類接收的成員。
(3) 在聲明派生類時增加的成員。


一般還應當自己定義派生類的構造函數和析構
函數,因爲構造函數和析構函數是不能從基類繼承的。


派生類是抽象基類的具體實現。


( 1) 公用繼承(public inheritance)
基類的公用成員和保護成員在派生類中保持原有訪問屬性,其私有成員
仍爲基類私有。
( 2) 私有繼承(private inheritance)
基類的公用成員和保護成員在派生類中成了私有成員。
其私有成員仍爲基類私有。
( 3) 受保護的繼承(protected inheritance)
基類的公用成員和保護成員在派生類中成了保護成員,其私有成員仍爲
基類私有。
保護成員的意思是: 不能被外界引用,但可以被派生類的成員引用,具
體的用法將在稍後介紹。




派生類構造函數名(總參數表列) : 基類構造函數名(參數表列) {派生
類中新增數據成員初始化語句}
( 1) 對基類數據成員初始化;
( 2) 對子對象數據成員初始化;
( 3) 對派生類數據成員初始化
派生類構造函數名(總參數表列) : 基類構造函數名(參數表列),子
對象名(參數表列){派生類中新增數成員據成員初始化語句}
① 調用基類構造函數,對基類數據成員初始化;
② 調用子對象構造函數,對子對象數據成員初始化;
③ 再執行派生類構造函數本身,對派生類數據成員初始化。


派生類的析構函數
派生類是不能繼承基類的析構函數的,也需要通過派生類的
析構函數去調用基類的析構函數。
基類的清理工作仍然由基類的析構函數負責。
調用的順序與構造函數正好相反




派生類同時繼承多個基類, 這種行爲
稱爲多重繼承(multiple inheritance)。
派生類構造函數名(總參數表列):基類1構造函數(參數表列),基
類2構造函數(參數表列),基類3構造函數(參數表列){派生類中新增
數成員據成員初始化語句}

 

 

 

 

 

/*虛基類*/

C++提供虛基類(virtual base class )的方法,使得在繼承間接共同基類時只保留一份成員。
class 派生類名: virtual 繼承方式 基類名
需要注意: 爲了保證虛基類在派生類中只繼承一次, 應當在該基類的所有直接派生類中聲明爲虛基類。


許多專業人員認爲:不要提倡在程序中使用多重繼承,只有在比較簡單和不易出現二義性的情況
或實在必要時才使用多重繼承,能用單一繼承解決的問題就不要使用多重繼承。


也是由於這個原因, 有些面向對象的程序設計語言(如Java, Smalltalk)並不支持多重繼承。


/*類的組合*/
在一個類中以另一個類的對象作爲數據成員的,稱爲類的組合(composition)。
類的組合和繼承一樣,是軟件重用的重要方式。

 

 

 

 

 

/*多態性*/

在面向對象方法中一般是這樣表述多態性的:向不同的對象發送同一個消息,
不同的對象在接收時會產生不同的行爲(即方法)。也就是說, 每個對象可以用自己的方式去響應共同。


靜態多態性是通過函數的重載實現的
動態多態性是通過虛函數


與基類成員同名的成員在不同的派生類中有不同的含義。也可以說, 多態性是“一個接口,多種方法”。


編譯系統按照同名覆蓋的原則決定調用的對象。如果想調用被覆蓋成員需加域名 ::

虛函數的作用是允許在派生類中重新定義與基類同名的函數,(動態性 運行時生成)
並且可以通過基類指針或引用來訪問基類和派生類中的同名函數。


虛函數的使用方法是:
(1)在基類用virtual聲明成員函數爲虛函數。
這樣就可以在派生類中重新定義此函數,爲它賦予新的功能,並能方便地被調用。
在類外定義虛函數時,不必再加virtual。
(2)在派生類中重新定義此函數,要求函數名、函數類型、函數參數個數
和類型全部與基類的虛函數相同,並根據派生類的需要重新定義函數體。
(3)定義一個指向基類對象的指針變量,並使它指向同一類族中需要調用
該函數的對象。
(4)通過該指針變量調用此虛函數,此時調用的就是指針變量指向的對象
的同名函數。
通過虛函數與指向基類對象的指針變量的配合使用,就能方便地調用同
一類族中不同類的同名函數,只要先用基類指針指向即可。


當一個類帶有虛函數時, 編譯系統會爲該類構造一個虛函數表(virtualfunction table,簡稱vtable), 
它是一個指針數組,存放每個虛函數的入口地址。系統在進行動態關聯時的時間開銷是很少的,故多態性是高效的。

 

 

 

 

 

/**虛析構函數**/

析構函數的作用是在對象撤銷之前做必要的“清理現場”的工作。
用new運算符建立了臨時對象 delete運算符撤銷對象
會發生一個情況:系統會只執行基類的析構函數,而不執行派生類的析構函數.


當基類的析構函數爲虛函數時,無論指針指的是同一類族中的哪一個類對象,系統會採用動態關聯,
如果希望能執行派生類Circle的析構函數,可以將基類的析構函數聲明爲虛析構函數,
最好把基類的析構函數聲明爲虛函數。這將使所有派生類的析構函數自動成爲虛函數。


專業人員一般都習慣聲明虛析構函數,即使基類並不需要析構函數,也顯式地定義一個函數體爲空的虛析構函數,
以保證在撤銷動態分配空間時能得到正確的處理。

 

 

 

 

 

/**純虛函數**/

只給出函數的原型,並在後面加上“=0”,如
virtual float area( )const =0;//純虛函數
這就將area聲明爲一個純虛函數(pure virtual function)。
純虛函數是在聲明虛函數時被“初始化”爲0的函數。


①純虛函數沒有函數體 ;
②最後面的“=0”並不表示函數返回值爲0,它只起形式上的作用,告訴編譯系統“這是純虛函數” ;
③這是一個聲明語句,最後應有分號 ;


它只是通知編譯系統:“在這裏聲明一個虛函數,留待派生類中定義”。
派生類中沒有對該函數定義,則該虛函數在派生類中仍然爲純虛函數。




/**抽象類**/
不用來定義對象而只作爲一種基本類型用作繼承的類,稱爲抽象類(abstract class ),
由於它常用作基類, 通常稱爲抽象基類(abstract base class )。凡是包含純虛函數的類都是抽象類。


因爲純虛函數是不能被調用的,包含純虛函數的類是無法建立對象的。抽象類的作用
是作爲一個類族的共同基類,或者說,爲一個類族提供一個公共接口。
zhu

轉自:https://blog.csdn.net/qq_17308321/article/details/53818698 

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