為什麼虛析構函數名不一樣
⑴ 為什麼基類與派生類的析構函數不一樣,卻可以實現多態
無關其它,要非這樣說,只能歸結於c++機制. 虛函數要求函數名一樣,其實現多態的本質是:
父類* =new 子類,但如此一來,指針就變成父類的了,delete 指針的時候,由於c++會指針類型來調用析構函數,這樣就調不到子類析構,有一解決辦法是把該父類指針轉成new時的子類指針,這樣就會調到子類析構,但很多情況下父類根本就不知道是否有子類,就不能盲目強轉,為了解決這一矛盾,就加了析構可以是虛函數,一般用在父類有virtual成員時,其析構必為virtual。
LZ想問的是虛函數要求名字一樣,而析構名字根本就不一樣怎麼可能是虛函數,因為析構是和類名一樣的,如果析構名字一樣就會出現類重定義了,它是析構名字和虛函數雙方妥協而要同時滿足多態機制的產物,當然,單從虛函數的角度來看它肯定是不滿足的。
⑵ 關於虛擬析構函數的問題
書不能讀死,這本書看不懂,另找一本對照一下。
隨便在網上找了個參考的:
構造函數不能用虛擬,因為用也沒用,不管是在棧上構造對象,還是在堆上構造對象,也不管你以後是否使用父類的指針或引用來指向或引用這個對象,在構造的那「一瞬間」,總歸要指明要構造對象的具體類型,所以,對象在構造過程中不存在運行時動態綁定的多態行為。
你理解這個意思嗎?舉了例子就明白了,通常,假如A是B的父類,
A* p = new B();
則對於虛擬函數f,可以通過A類的指針p直接調用到B類的函數,這就是運行時的多態:
p->f();
但你注意沒有,B類的對象卻必須通過「A* p = new B();」來構造,顯然不能通過「A* p = new A();」來構造一個B類對象——這是荒唐的,這只能構造一個A類的對象。所以構造函數虛擬無意義。
但析構函數就不同了,p明明是個A類的指針,如果析構函數不是虛擬的,那麼,你後面就必須這樣才能安全的刪除這個指針:
delete (B*)p;
但如果構造函數是虛擬的,就可以在運行時動態綁定到B類的析構函數,直接:
delete p;
就可以了。這就是虛析構函數的作用。而事實上,在運行時,你並不是總是能知道p所指對象的實際類型從而進行強制轉換,所以,C++語言既然要支持多態,也就必須支持虛擬析構。
⑶ 虛析構函數的介紹
虛析構函數是為了解決基類的指針指向派生類對象,並用基類的指針刪除派生類對象。如果某個類不包含虛函數,那一般是表示它將不作為一個基類來使用。當一個類不準備作為基類使用時,使析構函數為虛一般是個壞主意。因為它會為類增加一個虛函數表,使得對象的體積翻倍,還有可能降低其可移植性。所以基本的一條是:無故的聲明虛析構函數和永遠不去聲明一樣是錯誤的。實際上,很多人這樣總結:當且僅當類里包含至少一個虛函數的時候才去聲明虛析構函數。抽象類是准備被用做基類的,基類必須要有一個虛析構函數,純虛函數會產生抽象類,所以方法很簡單:在想要成為抽象類的類里聲明一個純虛析構函數。
⑷ 為什麼構造函數不能聲明為虛函數,析構函數可以
構造函數不能聲明為虛函數,析構函數可以聲明為虛函數,而且有時是必須聲明為虛函數。 不建議在構造函數和析構函數裡面調用虛函數。構造函數不能聲明為虛函數的原因是:1 構造一個對象的時候,必須知道對象的實際類型,而虛函數行為是在運行期間確定實際類型的。而在構造一個對象時,由於對象還未構造成功。編譯器無法知道對象 的實際類型,是該類本身,還是該類的一個派生類,或是更深層次的派生類。無法確定。。。2 虛函數的執行依賴於虛函數表。而虛函數表在構造函數中進行初始化工作,即初始化vptr,讓他指向正確的虛函數表。而在構造對象期間,虛函數表還沒有被初 始化,將無法進行。虛函數的意思就是開啟動態綁定,程序會根據對象的動態類型來選擇要調用的方法。然而在構造函數運行的時候,這個對象的動態類型還不完整,沒有辦法確定它到底是什麼類型,故構造函數不能動態綁定。(動態綁定是根據對象的動態類型而不是函數名,在調用構造函數之前,這個對象根本就不存在,它怎麼動態綁定?)編譯器在調用基類的構造函數的時候並不知道你要構造的是一個基類的對象還是一個派生類的對象。析構函數設為虛函數的作用: 解釋:在類的繼承中,如果有基類指針指向派生類,那麼用基類指針delete時,如果不定義成虛函數,派生類中派生的那部分無法析構。 例: #include "stdafx.h" #include "stdio.h"class A{public:A();virtual~A();};A::A(){}A::~A(){printf("Delete class APn");}class B : public A{public:B();~B();};B::B(){ }B::~B(){printf("Delete class BPn");}int main(int argc, char* argv[]){A *b=new B;delete b;return 0;} 輸出結果為:Delete class B Delete class A 如果把A的virtual去掉:那就變成了Delete class A也就是說不會刪除派生類里的剩餘部分內容,也即不調用派生類的虛函數因此在類的繼承體系中,基類的析構函數不聲明為虛函數容易造成內存泄漏。所以如果你設計一定類可能是基類的話,必須要聲明其為虛函數。正如Symbian中的CBase一樣。Note:1. 如果我們定義了一個構造函數,編譯器就不會再為我們生成默認構造函數了。 2. 編譯器生成的析構函數是非虛的,除非是一個子類,其父類有個虛析構,此時的函數虛特性來自父類。 3. 有虛函數的類,幾乎可以確定要有個虛析構函數。 4. 如果一個類不可能是基類就不要申明析構函數為虛函數,虛函數是要耗費空間的。 5. 析構函數的異常退出會導致析構不完全,從而有內存泄露。最好是提供一個管理類,在管理類中提供一個方法來析構,調用者再根據這個方法的結果決定下一步的操作。 6. 在構造函數不要調用虛函數。在基類構造的時候,虛函數是非虛,不會走到派生類中,既是採用的靜態綁定。顯然的是:當我們構造一個子類的對象時,先調用基類的構造函數,構造子類中基類部分,子類還沒有構造,還沒有初始化,如果在基類的構造中調用虛函數,如果可以的話就是調用一個還沒有被初始化的對象,那是很危險的,所以C++中是不可以在構造父類對象部分的時候調用子類的虛函數實現。但是不是說你不可以那麼寫程序,你這么寫,編譯器也不會報錯。只是你如果這么寫的話編譯器不會給你調用子類的實現,而是還是調用基類的實現。 7.在析構函數中也不要調用虛函數。在析構的時候會首先調用子類的析構函數,析構掉對象中的子類部分,然後在調用基類的析構函數析構基類部分,如果在基類的析構函數裡面調用虛函數,會導致其調用已經析構了的子類對象裡面的函數,這是非常危險的。8. 記得在寫派生類的拷貝函數時,調用基類的拷貝函數拷貝基類的部分,不能忘記了。
⑸ 析構函數和虛函數的用法和作用
置於「~」是析構函數;析構函數因使用"~"符號(邏輯非運算符),表示它為膩構造函數,加上類名稱來定義。
;析構函數也是特殊的類成員函數,它沒有返回類型,沒有參數,不能隨意調用,也沒有重載,只有在類對象的生命期結束的時候,由系統自動調用。
有適放內存空間的做用!
虛函數是C++多態的一種表現
例如:子類繼承了父類的一個函數(方法),而我們把父類的指針指向子類,則必須把父類的該函數(方法)設為virturl(虛函數)。
使用虛函數,我們可以靈活的進行動態綁定,當然是以一定的開銷為代價。
如果父類的函數(方法)根本沒有必要或者無法實現,完全要依賴子類去實現的話,可以把此函數(方法)設為virturl
函數名=0
我們把這樣的函數(方法)稱為純虛函數。
如果一個類包含了純虛函數,稱此類為抽象類
⑹ c++題,誰解釋下
典型的虛析構函數應用問題,在你的例子中,子類的對象並沒有被釋放,只釋放了基類部分,像你這樣使用虛函數會出問題,因此最好把基類的析構函數聲明為虛擬的,這樣才能保證在使用new時,能正確釋放資源,下面具體給你介紹一下為什麼要使用虛析構函數,以及你的程序為什麼沒有輸出YY吧。看了之後你就能讓程序輸出YY了。
虛析構函數
1. 為什麼需要虛析構函數:當使用new運算符動態分配內存時,基類的析構函數就應該定義為虛析構函數,不然就會出問題。比如類B由類A繼承而來,則有語句A *p= new A;delete p; 這時沒有問題,調用類A的析構函數釋放類A的資源。但如果再把類B的內存動態分配給指針p時如p= new B; delete p;如果基類的析構函數不是虛析構函數的話就會只調用基類A中的析構函數釋放資源,而不會調用派生類B的析構函數,這時派生類B的資源沒有被釋放。
2. 解決這個問題的方法是把基類的析構函數聲明為虛析構函數,即在析構函數前加virtual關見字,定義為虛析構函數時當用delete釋放派生類的資源時就會根據基類的析構函數自動調用派生類中的析構函數釋放派生類的資源。
3. 只要基類中的析構函數是虛析構函數,則該基類的派生類中的析構函數自動為虛析構函數,雖然派生類中的析構函數前沒有virtual關見字,析構函數名字也不一樣,但派生類中的析構函數被自動繼承為虛析構函數。
4. 如果要使用new運算符分配內存,最好將析構函數定義為虛析構函數。
⑺ 在C++中,能否聲明虛構函數為什麼能否聲明虛析構函數為什麼
原因如下:在C++-中不能聲明虛構造函數,多態是不同的對象對同一消息有不同的行為特性,虛函數作為運行過程中多態的基礎,主要是針對對象的,面構造函數是在對盤產生之前運行的,因此虛構造函數是沒有童義的。
在C++中可以聲明虛析構函數,析構函數的功能是在該類對象消亡之前進行一些必要的清理工作,如果一個類的析構函數是虛函數,那麼由它派生而來的所有子類的析構函數也是虛函數。
析構函數設置為虛函數之後,在使用指針引用時可以動態聯編,實理運行時的多態,保證使用基類的指針就能夠謂用適當的析構函數指針對不同的對象進行清理工作。
(7)為什麼虛析構函數名不一樣擴展閱讀:
虛函數的限制:
1、非類的成員函數不能定義為虛函數,類的成員函數中靜態成員函數和構造函數也不能定義為虛函數,但可以將析構函數定義為虛函數。實際上,優秀的程序員常常把基類的析構函數定義為虛函數。
因為將基類的析構函數定義為虛函數後,當利用delete刪除一個指向派生類定義的對象指針時,系統會調用相應的類的析構函數。而不將析構函數定義為虛函數時,只調用基類的析構函數。
2、只需要在聲明函數的類體中使用關鍵字「virtual」將函數聲明為虛函數,而定義函數時不需要使用關鍵字「virtual」。
3、當將基類中的某一成員函數聲明為虛函數後,派生類中的同名函數(函數名相同、參數列表完全一致、返回值類型相關)自動成為虛函數。
4、如果聲明了某個成員函數為虛函數,則在該類中不能出現和這個成員函數同名並且返回值、參數個數、類型都相同的非虛函數。在以該類為基類的派生類中,也不能出現和這個成員函數同名並且返回值、參數個數、類型都相同的非虛函數。
⑻ 關於C++ 類繼承中的虛析構函數
你第一個問題的理解是錯的,其實只要子類的析構函數是虛函數,子類和基類的析構函數是構成覆蓋關系的,因為盡管他們函數名不一樣,但因為每個類只有一個析構函數,所以c++規定他們是構成覆蓋關系的,所以兩全其美的方法就是基類的析構函數都定義為虛函數
⑼ 析構函數為什麼是虛函數
析構函數可以為虛函數,也可以不為虛函數。(更多的時候不為虛函數)。設計析構函數為虛函數,主要是考慮到繼承。
析構函數(destructor) 與構造函數相反,當對象結束其生命周期,如對象所在的函數已調用完畢時,系統自動執行析構函數。析構函數往往用來做「清理善後」 的工作(例如在建立對象時用new開辟了一片內存空間,delete會自動調用析構函數後釋放內存)。
函數介紹
與構造函數相反,當對象結束其生命周期,如對象所在的函數已調用完畢時,系統會自動執行析構函數。以C++語言為例:析構函數名也應與類名相同,只是在函數名前面加一個位取反符~,例如~stud( ),以區別於構造函數。它不能帶任何參數,也沒有返回值(包括void類型)。只能有一個析構函數,不能重載。
⑽ 請講一講析構函數和虛函數的用法和作用。
析構就是對象離開生存空間時執行的,用來清理分配的空間之類.
虛函數的作用:假如有類A.類A派生出類B.
那麼如果寫A* p = new B;時.就得到了一個指向類B的指針,這個指針的類型是A*
如果類A和類B中都有void Out()這么個函數.p->Out()將調用A::Out()函數
而如果把類A中的改成虛函數virtual void Out().p->Out()就將調用B::Out()函數.
就是這樣
下面抄幾段:
析構函數是「反向」的構造函數。它們在對象被撤消(回收)時調用。析構函數的名 稱除了最前面的「~」符號外,與類的名稱相同。例如,類String的析構函數是~string()。 析構函數通常用於當一個對象不再需要時,完成「消除」功能。
在函數中建立對象之後,這個對象作為局部對象開始生存,直到函數運行到遇見右括弧「}」才結束生存,此時調用析構函數。
對象的釋放發生在以下幾種情況,首發自學編程網:
·使用運算符new分配的對象被delete刪除。
·一個具有塊作用域的本地(自動)對象超出其作用域。
·臨時對象的生存期結束。
·程序結束運行。
·使用完全限定名顯示調用對象的析構函數。
有幾條規則約束著析構函數的說明:
·不能接受參量。
· 不能說明有任何返回類型(包括void)。
·不能用return語句返回值。
· 不能說明為const、volatile或static,但析構函數可以因說明為const、volatile或static的對象的析構而被調用。
·可以說明為虛擬的。使用虛析構函數,可以撤消對象而不必知道該對象的類型。由於使用虛擬函數機制,程序將調用該對象的正確的析構函數。
注意:在一個抽象類中,析構函數可以說明為虛函數。我們會在後面詳細介紹虛函數的概念。
虛函數去這看吧
http://www.pconline.com.cn/pce/empolder/gj/c/0507/665004.html
下面還有個虛析構的
http://www.wangchao.net.cn/bbsdetail_431181.html