小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

虛析構(gòu)函數(shù)(√)、純虛析構(gòu)函數(shù)(√)、虛構(gòu)造函數(shù)(X)

 9loong 2009-11-30
http://hi.baidu.com/jrckkyy/blog/item/679039d47034d909a08bb771.html
 
2009年04月08日 星期三 下午 03:23
一. 虛析構(gòu)函數(shù)

我們知道,為了能夠正確的調(diào)用對象的析構(gòu)函數(shù),一般要求具有層次結(jié)構(gòu)的頂級類定義其析構(gòu)函數(shù)為虛函數(shù)。因?yàn)樵赿elete一個抽象類指針時候,必須要通過虛函數(shù)找到真正的析構(gòu)函數(shù)。

如:

class Base
{
public:
    Base(){}
   
virtual ~Base(){}
};

class Derived: public Base
{
public:
    Derived(){};
   
~Derived(){};
}

void foo()
{
    Base
*pb;
    pb
= new Derived;
    delete pb;
}
這是正確的用法,會發(fā)生動態(tài)綁定,它會先調(diào)用Derived的析構(gòu)函數(shù),然后是Base的析構(gòu)函數(shù)

如果析構(gòu)函數(shù)不加virtual,delete pb只會執(zhí)行Base的析構(gòu)函數(shù),而不是真正的Derived析構(gòu)函數(shù)。
因?yàn)椴皇莢irtual函數(shù),所以調(diào)用的函數(shù)依賴于指向靜態(tài)類型,即Base

二. 純虛析構(gòu)函數(shù)
現(xiàn)在的問題是,我們想把Base做出抽象類,不能直接構(gòu)造對象,需要在其中定義一個純虛函數(shù)。如果其中沒有其他合適的函數(shù),可以把析構(gòu)函數(shù)定義為純虛的,即將前面的CObject定義改成:
class Base
{
public:
    Base(){}
   
virtual ~Base()= 0
};
可是,這段代碼不能通過編譯,通常是link錯誤,不能找到~Base()的引用 (gcc的錯誤報告)。這是因?yàn)?,析?gòu)函數(shù)、構(gòu)造函數(shù)和其他內(nèi)部函數(shù)不一樣,在調(diào)用時,編譯器需要產(chǎn)生一個調(diào)用鏈。也就是,Derived的析構(gòu)函數(shù)里面 隱含調(diào)用了Base的析構(gòu)函數(shù)。而剛才的代碼中,缺少~Base()的函數(shù)體,當(dāng)然會出現(xiàn)錯誤。

這里面有一個誤區(qū),有人認(rèn)為,virtual f()=0這種純虛函數(shù)語法就是沒有定義體的語義。
其實(shí),這是不對的。這種語法只是表明這個函數(shù)是一個純虛函數(shù),因此這個類變成了抽象類,不能產(chǎn)生對象。我們完全可以為純虛函數(shù)指定函數(shù)體 (http://www.research./~bs/bs_faq2.html#pure-virtual)。通常的純虛函數(shù)不需要函數(shù)體,是因?yàn)槲覀円话悴粫{(diào)用抽象類的這個函數(shù),只會調(diào)用派生類的對應(yīng)函數(shù)。這樣,我們就有了一個純虛析構(gòu)函數(shù)的函數(shù)體,上面的代碼需要改成:
class Base
{
public:
    Base()
    {
    }
   
virtual ~Base() = 0; //pure virtual
};

Base::
~Base()//function body
{
}

從語法角度來說,不可以將上面的析構(gòu)函數(shù)直接寫入類聲明中(內(nèi)聯(lián)函數(shù)的寫法)。這或許是一個不正交化的地方。但是這樣做的確顯得有點(diǎn)累贅

這個問題看起來有些學(xué)術(shù)化,因?yàn)橐话阄覀兺耆梢栽贐ase中找到一個更加適合的函數(shù),通過將其定義為沒有實(shí)現(xiàn)體的純虛函數(shù),而將整個類定義為抽象類。但這種技術(shù)也有一些應(yīng)用,如這個例子:
class Base  //abstract class
{
public:
   
virtual ~Base(){};//virtual, not pure
   virtual void Hiberarchy() const = 0;//pure virtual
};

void Base::Hiberarchy() const //pure virtual also can have function body
{
    std::cout
<<"Base::Hiberarchy";
}

class Derived : public Base
{
public:
    Derived(){}
   
virtual void Hiberarchy() const
    {
        CB::Hiberarchy();
        std::cout
<<"Derived::Hiberarchy";
    }
   
virtual void foo(){}
};


int main(){
    Base
* pb=new Derived();
    pb
->Hiberarchy();
    pb
->Base::Hiberarchy();
   
return 0;
}

在 這個例子中,我們試圖打印出類的繼承關(guān)系。在根基類中定義了虛函數(shù)Hiberarchy,然后在每個派生類中都重載此函數(shù)。我們再一次看到,由于想把 Base做成個抽象類,而這個類中沒有其他合適的方法成員可以定義為純虛的,我們還是只好將Hiberarchy定義為純虛的。(當(dāng)然,完全可以定 義~Base函數(shù),這就和上面的討論一樣了。^_^)

另外,可以看到,在main中有兩種調(diào)用方法,第一種是普通的方式,進(jìn)行動態(tài)鏈接,執(zhí)行虛函數(shù),得到結(jié)果"Derived::Hiberarchy";第二種是指定類的方式,就不再執(zhí)行虛函數(shù)的動態(tài)鏈接過程了,結(jié)果是"Base::Hiberarchy"。

通過上面的分析可以看出,定義純虛函數(shù)的真正目的是為了定義抽象類, 而并不是函數(shù)本身。與之對比,在java中,定義抽象類的語法是 abstract class,也就是在類的一級作指定(當(dāng)然虛函數(shù)還是也要加上abstract關(guān)鍵字)。是不是這種方式更好一些呢?在Stroustrup的《C++語 言的設(shè)計與演化》中我找到這樣一段話:

“我選擇的是將個別的函數(shù)描述為純虛的方式,沒有采用將完整的類聲明定義為抽象的形式,這是因?yàn)榧兲摵瘮?shù)的概念更加靈活一些。我很看重能夠分階段定義類的能力;也就是說,我發(fā)現(xiàn)預(yù)先定義一些純虛函數(shù),并把另外一些留給進(jìn)一步的派生類去定義也是很有用的”。

我 還沒有完全理解后一句話,我想從另外一個角度來闡述這個概念。那就是,在一個多層復(fù)雜類結(jié)構(gòu)中,中間層次的類應(yīng)該具體化一些抽象函數(shù),但很可能并不是所有 的。中間類沒必要知道是否具體化了所有的虛函數(shù),以及其祖先已經(jīng)具體化了哪些函數(shù),只要關(guān)注自己的職責(zé)就可以了。也就是說,中間類沒必要知道自己是否是一 個真正的抽象類,設(shè)計者也就不用考慮是否需要在這個中間類的類級別上加上類似abstract的說明了。

當(dāng)然,一個語言的設(shè)計有多種因素,好壞都是各個方面的。這只是一個解釋而已。

最后,總結(jié)一下關(guān)于虛函數(shù)的一些常見問題:

1) 虛函數(shù)是動態(tài)綁定的,也就是說,使用虛函數(shù)的指針和引用能夠正確找到實(shí)際類的對應(yīng)函數(shù),而不是執(zhí)行定義類的函數(shù)。這是虛函數(shù)的基本功能,就不再解釋了。

2) 構(gòu)造函數(shù)不能是虛函數(shù)。而且,在構(gòu)造函數(shù)中調(diào)用虛函數(shù),實(shí)際執(zhí)行的是父類的對應(yīng)函數(shù),因?yàn)樽约哼€沒有構(gòu)造好, 多態(tài)是被disable的。

3) 析構(gòu)函數(shù)可以是虛函數(shù),而且,在一個復(fù)雜類結(jié)構(gòu)中,這往往是必須的。

4) 將一個函數(shù)定義為純虛函數(shù),實(shí)際上是將這個類定義為抽象類,不能實(shí)例化對象。

5) 純虛函數(shù)通常沒有定義體,但也完全可以擁有。

6) 析構(gòu)函數(shù)可以是純虛的,但純虛析構(gòu)函數(shù)必須有定義體,因?yàn)槲鰳?gòu)函數(shù)的調(diào)用是在子類中隱含的。

7) 非純的虛函數(shù)必須有定義體,不然是一個錯誤。

8) 派生類的override虛函數(shù)定義必須和父類完全一致。除了一個特例,如果父類中返回值是一個指針或引用,子類override時可以返回這個指針(或引用)的派生。例如,在上面的例子中,在Base中定義了 virtual Base* clone(); 在Derived中可以定義為 virtual Derived* clone()。可以看到,這種放松對于Clone模式是非常有用的。
其他,有待補(bǔ)充。
 
(#)

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多