淺析C++構(gòu)造函數(shù)虛擬化
虛擬構(gòu)造函數(shù)
當(dāng)你有一個(gè)指針或引用,但是不知道其指向?qū)ο蟮恼鎸?shí)類型是什么時(shí),你可以調(diào)用虛擬函數(shù)來完成特定類型(type-specific)對(duì)象的行為。僅當(dāng)你還沒擁有一個(gè)對(duì)象但是你確切地知道想要對(duì)象的類型時(shí),你才會(huì)調(diào)用構(gòu)造函數(shù)。那么虛擬構(gòu)造函數(shù)又從何談起呢?
例如假設(shè)你編寫一個(gè)程序,用來進(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ì)象由NLComponent 對(duì)象的鏈表組成
public:
NewsLetter(istream& str);
...
private:
list<NLComponent*> components;
};
在NewsLetter中使用的list類是一個(gè)標(biāo)準(zhǔn)模板類(STL)。對(duì)象NewLetter不運(yùn)行時(shí)就會(huì)存儲(chǔ)在磁盤上。為了能夠通過位于磁盤的替代物來建立Newsletter對(duì)象,讓NewLetter的構(gòu)造函數(shù)帶有istream參數(shù)是一種很方便的方法。當(dāng)構(gòu)造函數(shù)需要一些核心的數(shù)據(jù)結(jié)構(gòu)時(shí),它就從流中讀取信息。此構(gòu)造函數(shù)的偽代碼是這樣的:
NewsLetter::NewsLetter(istream& str)
{
while (str) {
從str讀取下一個(gè)component對(duì)象;
把對(duì)象加入到newsletter的 components
對(duì)象的鏈表中去;
}
}
或者,把這種技巧用于另一個(gè)獨(dú)立出來的函數(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ù),用來在鏈表最后進(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ù)
還有一種特殊種類的虛擬構(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 constructor
{
return new TextBlock(*this);
}
...
};
class Graphic: public NLComponent {
public:
virtual Graphic * clone() const // virtual copy constructor
{
return new Graphic(*this);
}
...
};
類的虛擬拷貝構(gòu)造函數(shù)只是調(diào)用它們真正的拷貝構(gòu)造函數(shù)。因此”拷貝”的含義與真正的拷貝構(gòu)造函數(shù)相同。如果真正的拷貝構(gòu)造函數(shù)只做了簡單的拷貝,那么虛擬拷貝構(gòu)造函數(shù)也做簡單的拷貝。如果真正的拷貝構(gòu)造函數(shù)做了全面的拷貝,那么虛擬拷貝構(gòu)造函數(shù)也做全面的拷貝。
注意上述代碼的實(shí)現(xiàn)利用了最近才被采納的較寬松的虛擬函數(shù)返回值類型規(guī)則。被派生類重定義的虛擬函數(shù)不用必須與基類的虛擬函數(shù)具有一樣的返回類型。如果函數(shù)的返回類型是一個(gè)指向基類的指針(或一個(gè)引用),那么派生類的函數(shù)可以返回一個(gè)指向基類的派生類的指針(或引用)。這不是C++的類型檢查上的漏洞,它使得又可能聲明象虛擬構(gòu)造函數(shù)這樣的函數(shù)。這就是為什么TextBlock的clone函數(shù)能夠返回TextBlock*和Graphic的clone能夠返回Graphic*的原因,即使NLCompo-nent的clone返回值類型為NLComponent*。
在NLComponent中的虛擬拷貝構(gòu)造函數(shù)能讓實(shí)現(xiàn)NewLetter的(正常的)拷貝構(gòu)造函數(shù)變得很容易:
class NewsLetter {
public:
NewsLetter(const NewsLetter& rhs);
...
private:
list<NLComponent*> components;
};
NewsLetter::NewsLetter(const NewsLetter& rhs)
{
// 遍歷整個(gè)rhs鏈表,使用每個(gè)元素的虛擬拷貝構(gòu)造函數(shù)
// 把元素拷貝進(jìn)這個(gè)對(duì)象的component鏈表。
// 有關(guān)下面代碼如何運(yùn)行的詳細(xì)情況,請(qǐng)參見條款35。
for (list<NLComponent*>::const_iterator it = rhs.components.begin(); it != rhs.components.end(); ++it)
{
// "it" 指向rhs.components的當(dāng)前元素,調(diào)用元素的clone函數(shù),
// 得到該元素的一個(gè)拷貝,并把該拷貝放到
//這個(gè)對(duì)象的component鏈表的尾端。
components.push_back((*it)->clone());
}
}
遍歷被拷貝的NewsLetter對(duì)象中的整個(gè)component鏈表,調(diào)用鏈表內(nèi)每個(gè)元素對(duì)象的虛擬構(gòu)造函數(shù)。我們?cè)谶@里需要一個(gè)虛擬構(gòu)造函數(shù),因?yàn)殒湵碇邪赶騈LComponent對(duì)象的指針,但是我們知道其實(shí)每一個(gè)指針不是指向TextBlock對(duì)象就是指向Graphic對(duì)象。無論它指向誰,我們都想進(jìn)行正確的拷貝操作,虛擬構(gòu)造函數(shù)能夠?yàn)槲覀冏龅竭@點(diǎn)。
以上內(nèi)容基本都來自《More Effective C++》。
以上就是淺析C++構(gòu)造函數(shù)虛擬化的詳細(xì)內(nèi)容,更多關(guān)于C++構(gòu)造函數(shù)虛擬化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- c++ 子類構(gòu)造函數(shù)初始化及父類構(gòu)造初始化的使用
- 詳解C++ 拷貝構(gòu)造函數(shù)
- C++語法詳解之封裝、構(gòu)造函數(shù)、析構(gòu)函數(shù)
- 詳解C++中構(gòu)造函數(shù),拷貝構(gòu)造函數(shù)和賦值函數(shù)的區(qū)別和實(shí)現(xiàn)
- C++中構(gòu)造函數(shù)的參數(shù)缺省的詳解
- C++ 中構(gòu)造函數(shù)的實(shí)例詳解
- C++中的移動(dòng)構(gòu)造函數(shù)及move語句示例詳解
- C++類繼承之子類調(diào)用父類的構(gòu)造函數(shù)的實(shí)例詳解
- 詳解C++ 編寫String 的構(gòu)造函數(shù)、拷貝構(gòu)造函數(shù)、析構(gòu)函數(shù)和賦值函數(shù)
- C++ 構(gòu)造函數(shù)中使用new時(shí)注意事項(xiàng)
相關(guān)文章
QT使用QML實(shí)現(xiàn)地圖繪制虛線的示例代碼
QML提供了MapPolyline用于在地圖上繪制線段,這篇文章主要為大家詳細(xì)介紹了QT如何使用QML實(shí)現(xiàn)在地圖上繪制虛線,需要的小伙伴可以參考一下2023-07-07
C語言中怎么在main函數(shù)開始前執(zhí)行函數(shù)
C語言中怎么在main函數(shù)開始前執(zhí)行函數(shù)呢?下面小編就大家詳細(xì)的介紹一下。需要的朋友可以過來參考下,希望對(duì)大家有所幫助2013-10-10
C/C++實(shí)現(xiàn)經(jīng)典象棋游戲的示例代碼
中國象棋是起源于中國的一種棋,屬于二人對(duì)抗性游戲的一種,在中國有著悠久的歷史。本文將利用C++實(shí)現(xiàn)這一經(jīng)典游戲,快跟隨小編一起學(xué)習(xí)一下吧2022-06-06
C語言用棧和隊(duì)列實(shí)現(xiàn)的回文檢測(cè)功能示例
這篇文章主要介紹了C語言用棧和隊(duì)列實(shí)現(xiàn)的回文檢測(cè)功能,結(jié)合具體實(shí)例形式分析了C語言棧和隊(duì)列的定義及使用棧和隊(duì)列進(jìn)行回文檢測(cè)的操作技巧,需要的朋友可以參考下2017-06-06
QT實(shí)現(xiàn)年會(huì)抽獎(jiǎng)小軟件的示例代碼
本文主要介紹了QT實(shí)現(xiàn)年會(huì)抽獎(jiǎng)小軟件的示例代碼,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
C++實(shí)現(xiàn)動(dòng)態(tài)分配const對(duì)象實(shí)例
這篇文章主要介紹了C++實(shí)現(xiàn)動(dòng)態(tài)分配const對(duì)象實(shí)例,包括了const對(duì)象的創(chuàng)建、刪除及應(yīng)用實(shí)例,需要的朋友可以參考下2014-10-10

