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