從字面來(lái)看,談?wù)摗疤摂M構(gòu)造函數(shù)”沒(méi)有意義。當(dāng)有一個(gè)指針或引用,但是不知道其指向?qū)ο蟮恼鎸?shí)類型是什么時(shí),可以調(diào)用虛擬函數(shù)來(lái)完成特定類型(type-specific)對(duì)象的行為。僅當(dāng)還沒(méi)擁有一個(gè)對(duì)象但是又確切地知道想要的對(duì)象的類型時(shí),才會(huì)調(diào)用構(gòu)造函數(shù)。那么虛擬構(gòu)造函數(shù)又從何談起呢?
很簡(jiǎn)單。盡管虛擬構(gòu)造函數(shù)看起來(lái)好像沒(méi)有意義,其實(shí)它們有非常的用處.例如,假設(shè)編寫(xiě)一個(gè)程序,用來(lái)進(jìn)行新聞報(bào)道的工作,每一條新聞報(bào)道都由文字或圖片組成。可以這樣管理它們:
class NLComponent {//用于 newsletter components
public:// 的抽象基類
... //包含至少一個(gè)純虛函數(shù)
};
class TextBlock: public NLComponent {
public:
... // 不包含純虛函數(shù)
};
class Graphic: public NLComponent {
public:
... // 不包含純虛函數(shù)
};
class NewsLetter { // 一個(gè) newsletter 對(duì)象
public:// 由NLComponent 對(duì)象
... // 的鏈表組成
private:
list<NLComponent*> components;
};
在NewsLetter中使用的list類是一個(gè)標(biāo)準(zhǔn)模板類(STL)。list類型對(duì)象的行為特性有些象雙向鏈表,盡管它沒(méi)有以這種方法來(lái)實(shí)現(xiàn)。對(duì)象NewLetter不運(yùn)行時(shí)就會(huì)存儲(chǔ)在磁盤(pán)上。為了能夠通過(guò)位于磁盤(pán)的替代物來(lái)建立Newsletter對(duì)象,讓NewLetter的構(gòu)造函數(shù)帶有istream參數(shù)是一種很方便的方法。當(dāng)構(gòu)造函數(shù)需要一些核心的數(shù)據(jù)結(jié)構(gòu)時(shí),它就從流中讀取信息:
class NewsLetter {
public:
NewsLetter(istream& str);
...
};
此構(gòu)造函數(shù)的偽代碼是這樣的:
NewsLetter::NewsLetter(istream& str)
{
while (str) {
從str讀取下一個(gè)component對(duì)象;
把對(duì)象加入到newsletter的 components對(duì)象的鏈表中去;
}
}
或者,把這種技巧用于另一個(gè)獨(dú)立出來(lái)的函數(shù)叫做readComponent,如下所示:
class NewsLetter {
public:
...
private:
// 為建立下一個(gè)NLComponent對(duì)象從str讀取數(shù)據(jù),
// 建立component 并返回一個(gè)指針。
static NLComponent * readComponent(istream& str);
...
};
NewsLetter::NewsLetter(istream& str)
{
while (str) {
// 把readComponent返回的指針添加到components鏈表的最后,
// \"push_back\" 一個(gè)鏈表的成員函數(shù),用來(lái)在鏈表最后進(jìn)行插入操作。
components.push_back(readComponent(str));
}
}
考慮一下readComponent所做的工作。它根據(jù)所讀取的數(shù)據(jù)建立了一個(gè)新對(duì)象,或是TextBlock或是Graphic。因?yàn)樗芙⑿聦?duì)象,它的行為與構(gòu)造函數(shù)相似,而且因?yàn)樗芙⒉煌愋偷膶?duì)象,我們稱它為虛擬構(gòu)造函數(shù)。虛擬構(gòu)造函數(shù)是指能夠根據(jù)輸入給它的數(shù)據(jù)的不同而建立不同類型的對(duì)象。虛擬構(gòu)造函數(shù)在很多場(chǎng)合下都有用處,從磁盤(pán)(或者通過(guò)網(wǎng)絡(luò)連接,或者從磁帶機(jī)上)讀取對(duì)象信息只是其中的一個(gè)應(yīng)用。
還有一種特殊種類的虛擬構(gòu)造函數(shù)――虛擬拷貝構(gòu)造函數(shù)――也有著廣泛的用途。虛擬拷貝構(gòu)造函數(shù)能返回一個(gè)指針,指向調(diào)用該函數(shù)的對(duì)象的新拷貝。因?yàn)檫@種行為特性,虛擬拷貝構(gòu)造函數(shù)的名字一般都是copySelf,cloneSelf或者是象下面這樣就叫做clone。很少會(huì)有函數(shù)能以這么直接的方式實(shí)現(xiàn)它:
class NLComponent {
public:
// declaration of virtual copy constructor
virtual NLComponent * clone() const = 0;
...
};
class TextBlock: public NLComponent {
public:
virtual TextBlock * clone() const// virtual copy
{ return new TextBlock(*this); } // constructor
...
};
class Graphic: public NLComponent {
public:
virtual Graphic * clone() const// virtual copy
{ return new Graphic(*this); } // constructor
...
};