天天看點

C++ Primer 學習筆記_80_模闆與泛型程式設計 --類模闆成員模闆與泛型程式設計

引言:

這一節我們介紹怎樣實作前面提到的Queue模闆類。

标準庫将queue實作為其他容器之上的擴充卡。為了強調在使用低級資料結構中設計的程式設計要點,我們将Queue實作為連結清單。實際上,在我們的實作中使用标準庫可能是個更好的決定!!-_-。

1、Queue的實作政策

如圖所示,我們實作兩個類:

1)QueueItem類表示Queue的連結清單中的節點,該類有兩個資料成員item和next:

a. item儲存Queue中元素的值,它的類型随Queue的每個執行個體而變化;

b. next是隊列中指向下一QueueItem對象的指針。

2)Queue類提供16.1.2節描述的接口函數,Queue類也有兩個資料成員:head和tail,這些成員是QueueItem指針。

像标準容器一樣,Queue類将複制指定給它的值。

2、QueueItem類

每當執行個體化一個Queue類的時候,也将執行個體化QueueItem的相同版本。如:如果建立Queue<int>,則将執行個體化一個夥伴類QueueItem<int>。

QueueItem類為私有類–他沒有公共接口。我們定義這個類隻是為了實作Queue,并不想用于一般目的。需要将Queue類設為QueueItem的友元,以便Queue的成員能夠通路QueueItem的成員。

【注解】

在類模闆的作用域内部,可以用它的非限定名字引用該類。

3、Queue類

 private實用函數destroy和 copy_elems将完成釋放Queue中的元素以及從另一Queue複制元素到這個Queue的任務。複制控制成員用于管理資料成員head和 tail,head和 tail是指向 Queue中首尾元素的指針,這些成員是QueueItem<Type>類型的值。

Queue類實作了幾個成員函數:

1)預設構造函數,将head和tail指針置0,指明目前Queue為空。

2)複制構造函數,初始化head和tail,并調用copy_item從它的初始器中複制元素。

3)幾個front函數,傳回頭元素的值。這些函數不進行檢查:

4、模闆作用域中模闆類型的引用

通常,當使用類模闆的名字的時候,必須指定模闆形參。但是有個例外:在類本身的作用域内部,可以使用類模闆的非限定名。例如,在預設構造函數和複制構造函數的聲明中,名字Queue是Queue<Type>縮寫表示。實質上,編譯器推斷,當我們引用類的名字時,引用的是同一版本。是以,複制構造函數定義其實等價于:

但是編譯器會為類中使用的其他模闆的模闆形參進行這樣的推斷,是以,在聲明夥伴類QueueItem的指針時,必須指定類型形參:

這些聲明指出,對于Queue類的給定執行個體化,head和 tail指向為同一模闆形參執行個體化的QueueItem類型的對象,即,在Queue<int>執行個體化的内部,head 和 tail的類型是QueueItem<int>*。在 head和 tail成員的定義中省略模闆形參将是錯誤的:

一、類模闆成員函數

類模闆成員函數的定義具有如下形式:

1、必須以關鍵字template開頭,後接類的模闆形參表;

2、必須指出它是哪個類的成員;

3、類名必須包含其模闆形參。

如:

1、destroy函數

2、pop函數

  pop函數假設使用者不會在空Queue上調用pop。該函數的唯一技巧是:記得保持指向該元素的一個單獨指針,以便在重置head指針之後可以删除元素。

3、push函數

這個函數首先配置設定新的QueueItem對象,用傳遞的值初始化它。幾點說明:

1)QueueItem構造函數将實參複制到QueueItem對象的 item成員。像标準容器所做的一樣,Queue類存儲所給元素的副本。

2)如果item為類類型,item的初始化使用item所具有任意類型的複制構造函數。

3)QueueItem構造函數還将next指針初始化為0,以指出該元素沒有指向其他QueueItem對象。在Queue的末尾添加元素,将next置0正是我們所希望的。

建立和初始化新元素之後,必須将它鍊入Queue,如果Queue為空,則head和tail都應該指向這個元素。如果Queue中已經有元素了,則使目前tail元素指向這個新元素。舊的tail不再是最後一個元素了,這也是通過使tail指向新構造的元素指明的。

4、copy_elem函數

該函數的目的就是提供給指派操作符和複制構造函數使用:

【附:指派操作符[P551習題16.32]】

5、模闆成員函數的執行個體化

類模闆的成員函數本身也是函數模闆。像任何其他函數模闆一樣,需要使用類模闆的成員函數産生該成員的執行個體化。與其他函數模闆不同的是,在執行個體化類模闆成員函數的時候,編譯器不執行模闆實參推斷,相反,類模闆成員函數的模闆形參由調用該函數的對象的類型确定。例如,當調用Queue<int>類型對象的push成員時,執行個體化push函數為:

對象的模闆實參能夠确定成員函數模闆實參,這一事實意味着,調用類模闆成員函數比調用類似函數模闆更靈活。用模闆形參定義的函數函數形參的實參允許進行正常轉換:

6、何時執行個體化類和成員

類模闆的成員函數隻有為程式所用才進行初始化。這樣,用于執行個體化模闆的類型隻需滿足實際使用的操作的要求。

定義模闆類型的對象時,該定義導緻執行個體化類模闆。定義對象也會執行個體化用于初始化該對象的任一構造函數,以及該構造函數調用的任意成員:

第一個語句執行個體化Queue類及其預設構造函數,第二個語句執行個體化push成員函數。

将依次執行個體化夥伴類QueueItem<string>及其構造函數。

Queue類中的QueueItem成員是指針。類模闆的指針定義不會對類進行初始化,隻有用到這樣的指針時才會對類進行執行個體化。是以,在建立Queue對象時不會執行個體化QueueItem類,相反在使用諸如front、push或pop這樣的Queue成員時,才會執行個體化QueueItem類。

繼續閱讀