簡要解讀C++的動態(tài)和靜態(tài)關聯以及虛析構函數
C++靜態(tài)關聯與動態(tài)關聯、C++是怎樣實現多態(tài)性的
在現實生活中,多態(tài)性的例子是很多的。我們分析一下人是怎樣處理多 態(tài)性的。例如,新生被錄取人大學,在人學報到時,先有一名工作人員審查材料,他的職責是甄別資格,然后根據錄取通知書上注明的錄取的系和專業(yè),將材料轉到有關的系和專業(yè),辦理具體的注冊人學手續(xù),也可以看作調用不同部門的處理程序辦理入學手續(xù)。在學 生眼里,這名工作人員是總的人口,所有新生辦入學手續(xù)都要經過他。學生拿的是統一的錄取通知書,但實際上分屬不同的系,要進行不同的注冊手續(xù),這就是多態(tài)。那么,這名工 作人員怎么處理多態(tài)呢?憑什么把它分發(fā)到哪個系呢?就是根據錄取通知書上的一個信 息(你被錄取入本校某某專業(yè))??梢姡獏^(qū)分就必須要有相關的信息,否則是無法判別的。
同樣,編譯系統要根據已有的信息,對同名函數的調用作出判斷。例如函數的重載, 系統是根據參數的個數和類型的不同去找與之匹配的函數的。對于調用同一類族中的虛函數,應當在調用時用一定的方式告訴編譯系統,你要調用的是哪個類對象中的函數。例如可以直接提供對象名,如studl.display()或grad1.display()。這樣編譯系統在對程序進行編譯時,即能確定調用的是哪個類對象中的函數。
確定調用的具體對象的過程稱為關聯(binding)。binding原意是捆綁或連接,即把兩樣東西捆綁(或連接)在一起。在這里是指把一個函數名與一個類對象捆綁在一起,建立關聯。一般地說,關聯指把一個標識符和一個存儲地址聯系起來。在計算機字典中可以査到,所謂關聯,是指計算機程序中不同的部分互相連接的過程。有些書中把binding譯為聯編、編聯、束定、或兼顧音和意,稱之為綁定。作者認為:從意思上說,關聯比較確切, 也好理解。但是有些教程中用了聯編這個術語。 大家在看到這個名詞時,應當知道指的就是本節(jié)介紹的關聯。
順便說一句題外話,計算機領域中大部分術語是從外文翻譯過來的,有許多譯名是譯得比較好的,能見名知意的。但也有一些則令人費解,甚至不大確切。例如在某些介紹計算機語言的書籍中,把project譯為“工程”,使人難以理解,其實譯為“項目”比較確切。 有些介紹計算機應用的書中充斥大量的術語,初聽起來好像很唬人、很難懂,許多學習 C++的人往往被大量的專門術語嚇住了,又難以理解其真正含義,不少人“見難而退”。 這個問題成為許多人學習C++的攔路虎。因此,應當提倡用通俗易懂的方法去闡明復雜的概念。其實,有許多看起來深奧難懂的概念和術語,捅破窗戶紙后是很簡單的。建議讀者在初學時千萬不要糾纏于名詞術語的字面解釋上,而要掌握其精神實質和應用方法。
說明:與其他編程語言相比,例如Java、C#等,C++的語法是最豐富最靈活的,同樣也是最難掌握的,大家要循序漸進,莫求速成,在編程實踐中不斷翻閱和記憶。
前面所提到的函數重載和通過對象名調用的虛函數,在編譯時即可確定其調用的虛函數屬于哪一個類,其過程稱為靜態(tài)關聯(static binding),由于是在運行前進行關聯的, 故又稱為早期關聯(early binding)。函數重載屬靜態(tài)關聯。
在調用虛函數時并沒有指定對象名,那么系統是怎樣確定關聯的呢?讀者可以看到,是通過基類指針與虛函數的結合來實現多態(tài)性的。先定義了一個指向基類的指針變量,并使它指向相應的類對象,然后通過這個基類指針去調用虛函數(例如“pt->display()”)。顯然,對這樣的調用方式,編譯系統在編譯該行時是無法確定調用哪一個類對象的虛函數的。因為編譯只作靜態(tài)的語法檢査,光從語句形式(例如“pt->display();”)是無法確定調用對象的。
在這樣的情況下,編譯系統把它放到運行階段處理,在運行階段確定關聯關系。在運行階段,基類指針變量先指向了某一個類對象,然后通過此指針變量調用該對象中的函數。此時調用哪一個對象的函數無疑是確定的。例如,先使pt指向grad1,再執(zhí)行“pt->display()”,當然是調用grad1中的display函數。由于是在運行階段把虛函數和類對象“綁定”在一起的,因此,此過程稱為動態(tài)關聯(dynamic binding)。這種多態(tài)性是動態(tài)的多態(tài)性,即運行階段的多態(tài)性。
在運行階段,指針可以先后指向不同的類對象,從而調用同一類族中不同類的虛函數。由于動態(tài)關聯是在編譯以后的運行階段進行的,因此也稱為滯后關聯(late binding) 。
C++虛析構函數詳解
當派生類的對象從內存中撤銷時一般先調用派生類的析構函數,然后再調用基類的析構函數。但是,如果用new運算符建立了臨時對象,若基類中有析構函數,并且定義了一個指向該基類的指針變量。在程序用帶指針參數的delete運算符撤銷對象時,會發(fā)生一個情況:系統會只執(zhí)行基類的析構函數,而不執(zhí)行派生類的析構函數。
[例] 基類中有非虛析構函數時的執(zhí)行情況。為簡化程序,只列出最必要的部分。
#include <iostream>
using namespace std;
class Point //定義基類Point類
{
public:
Point( ){} //Point類構造函數
~Point(){cout<<"executing Point destructor"<<endl;} //Point類析構函數
};
class Circle:public Point //定義派生類Circle類
{
public:
Circle( ){} //Circle類構造函數
~Circle( ){cout<<"executing Circle destructor"<<endl;} //Circle類析構函數
private:
int radius;
};
int main( )
{
Point *p=new Circle; //用new開辟動態(tài)存儲空間
delete p; //用delete釋放動態(tài)存儲空間
return 0;
}
這只是一個示意的程序。p是指向基類的指針變量,指向new開辟的動態(tài)存儲空間,希望用detele釋放p所指向的空間。但運行結果為:
executing Point destructor
表示只執(zhí)行了基類Point的析構函數,而沒有執(zhí)行派生類Circle的析構函數。
如果希望能執(zhí)行派生類Circle的析構函數,可以將基類的析構函數聲明為虛析構函數,如:
virtual ~Point(){cout<<″executing Point destructor″<<endl;}
程序其他部分不改動,再運行程序,結果為:
executing Circle destructor executing Point destructor
先調用了派生類的析構函數,再調用了基類的析構函數,符合人們的愿望。
當基類的析構函數為虛函數時,無論指針指的是同一類族中的哪一個類對象,系統會采用動態(tài)關聯,調用相應的析構函數,對該對象進行清理工作。
如果將基類的析構函數聲明為虛函數時,由該基類所派生的所有派生類的析構函數也都自動成為虛函數,即使派生類的析構函數與基類的析構函數名字不相同。
最好把基類的析構函數聲明為虛函數。這將使所有派生類的析構函數自動成為虛函數。這樣,如果程序中顯式地用了delete運算符準備刪除一個對象,而delete運算符的操作對象用了指向派生類對象的基類指針,則系統會調用相應類的析構函數。
虛析構函數的概念和用法很簡單,但它在面向對象程序設計中卻是很重要的技巧。
專業(yè)人員一般都習慣聲明虛析構函數,即使基類并不需要析構函數,也顯式地定義一個函數體為空的虛析構函數,以保證在撤銷動態(tài)分配空間時能得到正確的處理。
構造函數不能聲明為虛函數。這是因為在執(zhí)行構造函數時類對象還未完成建立過程,當然談不上函數與類對象的綁定。
上一篇:深入解析C++中類的多重繼承
欄 目:C語言
本文標題:簡要解讀C++的動態(tài)和靜態(tài)關聯以及虛析構函數
本文地址:http://www.jygsgssxh.com/a1/Cyuyan/2678.html
您可能感興趣的文章
- 04-02c語言沒有round函數 round c語言
- 01-10深入理解C++中常見的關鍵字含義
- 01-10使用C++實現全排列算法的方法詳解
- 01-10c++中inline的用法分析
- 01-10用C++實現DBSCAN聚類算法
- 01-10全排列算法的非遞歸實現與遞歸實現的方法(C++)
- 01-10C++大數模板(推薦)
- 01-10淺談C/C++中的static與extern關鍵字的使用詳解
- 01-10深入C/C++浮點數在內存中的存儲方式詳解
- 01-10深入理解C/C++混合編程


閱讀排行
本欄相關
- 04-02c語言函數調用后清空內存 c語言調用
- 04-02func函數+在C語言 func函數在c語言中
- 04-02c語言的正則匹配函數 c語言正則表達
- 04-02c語言用函數寫分段 用c語言表示分段
- 04-02c語言中對數函數的表達式 c語言中對
- 04-02c語言編寫函數冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數 round c語言
- 04-02c語言分段函數怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數 c語言中怎
- 04-02c語言調用函數求fibo C語言調用函數求
隨機閱讀
- 01-10SublimeText編譯C開發(fā)環(huán)境設置
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 04-02jquery與jsp,用jquery
- 01-11ajax實現頁面的局部加載
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10delphi制作wav文件的方法
- 01-10C#中split用法實例總結
- 08-05dedecms(織夢)副欄目數量限制代碼修改


