从零开始学C++之模板(三):缺省模板参数(借助标准模板容器实现Stack模板)、成员模板、关键字typename...
一、缺省模板參數
回顧前面的文章,都是自己管理stack的內存,無論是鏈棧還是數組棧,能否借助標準模板容器管理呢?答案是肯定的,只需要多傳一個模板參數即可,而且模板參數還可以是缺省的,如下:
template <typename T, typename CONT = std::deque<T> >
class Stack
{
…
private:
????CONT?c_;
};
如果沒有傳第二個參數,默認為deque 雙端隊列,當然我們也可以傳遞std::vector<T>
?
下面程序借助標準模板容器管理內存來實現stack模板類:
Stack.h:
?
C++ Code?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | ? | #ifndef?_STACK_H_ #define?_STACK_H_ #include?<exception> #include?<deque> using? namespace?std; template?< typename?T,? typename?CONT?=?deque<T>?> class?Stack { public: ????Stack()?:?c_() ????{ ????} ????~Stack() ????{ ????} ???? void?Push( const?T?&elem) ????{ ????????c_.push_back(elem); ????} ???? void?Pop() ????{ ????????c_.pop_back(); ????} ????T?&Top() ????{ ???????? return?c_.back(); ????} ???? const?T?&Top()? const ????{ ???????? return?c_.back(); ????} ???? bool?Empty()? const ????{ ???????? return?c_.empty(); ????} private: ????CONT?c_; }; #endif? //?_STACK_H_ |
?
main.cpp:
?
C++ Code?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | ? | #include? "Stack.h" #include?<iostream> #include?<vector> using? namespace?std; int?main( void) { ???? /*Stack<int>?s;*/ ????Stack< int,?vector< int>?>?s; ????s.Push( 1); ????s.Push( 2); ????s.Push( 3); ???? while?(!s.Empty()) ????{ ????????cout?<<?s.Top()?<<?endl; ????????s.Pop(); ????} ???? return? 0; } |
?
?
輸出為 3 2 1
即如果沒有傳遞第二個參數,堆棧和壓棧等操作直接調用deque<int> 的成員函數,也由deque<int> 管理內存。
如程序中傳遞vector<int> ,則由vector<int> 成員函數處理。
二、成員模板
來看下面的例子:
?
C++ Code?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ? | #include?<iostream> using? namespace?std; template?< typename?T> class?MyClass { private: ????T?value; public: ???? void?Assign( const?MyClass<T>?&x) ????{ ????????value?=?x.value; ????} }; int?main( void) { ????MyClass< double>?d; ????MyClass< int>?i; ????d.Assign(d);???????? //?OK ????d.Assign(i);???????? //?Error ???? return? 0; } |
?
?
因為i 和 d 的類型不同,故會編譯出錯。可以用成員模板的方法解決:C++ Code?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | ? | #include?<iostream> using? namespace?std; template?< typename?T> class?MyClass { private: ????T?value; public: ????MyClass()?{} ???? template?< class?X> ????MyClass( const?MyClass<X>?&x)?:?value(x.GetValue()) ????{ ????} ???? template?< class?X> ???? void?Assign( const?MyClass<X>?&x) ????{ ????????value?=?x.GetValue(); ????} ????T?GetValue()? const ????{ ???????? return?value; ????} }; int?main( void) { ????MyClass< double>?d; ????MyClass< int>?i; ????d.Assign(d);???????? //?OK ????d.Assign(i);???????? //?OK ????MyClass< double>?d2(i); ???? return? 0; } |
為了支持 ?MyClass<double>?d2(i); 故也要將拷貝構造函數實現為成員模板,同理,如果想支持 d = i ; 也要講賦值運算符實現為成員
模板。 實際上auto_ptr<class> 中的實現就使用了成員模板,因為要支持類似下面的運算:
auto_ptr<X> x;
auto_ptr<Y> y;
x = y;
三、typename 關鍵字
看下面的例子:
C++ Code?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ? | #include?<iostream> using? namespace?std; template?< typename?T> class?MyClass { private: ???? typename?T::SubType?*ptr_; }; class?Test { public: ???? typedef? int?SubType; }; int?main( void) { ????MyClass<Test>?mc; ???? return? 0; } |
typename?T::SubType?*ptr_; 如果前面沒有typename 修飾,則SubType會被認為是T類型內部的靜態數據成員,推導下去,* 就不再認
為是指針,而被認為是乘號,編譯的時候就出錯了。加上修飾,就知道SubType 是T 內部的自定義類型,ptr是指向這種類型的指
針,編譯通過。
?
四、派生類與模板、面向對象與泛型編程
(一)、派生類與模板
1、為了運行的效率,類模板是相互獨立的,即獨立設計,沒有使用繼承的思想。對類模板的擴展是采用適配器(adapter)來完成的。通用性是模板庫的設計出發點之一,這是由泛型算法(algorithm)和函數對象(functor)等手段達到的。
2、派生的目標之一也是代碼的復用和程序的通用性,最典型的就是MFC,派生類的優點是可以由簡到繁,逐步深入,程序編制過程中可以充分利用前面的工作,一步步完成一個復雜的任務。
3、模板追求的是運行效率,而派生追求的是編程的效率。
(二)、面向對象與泛型編程
1、面向對象與泛型都依賴于某個形式的多態
面向對象
動態多態(虛函數)
泛型
靜態多態(模板類,模板函數)
2、面向對象中的多態在運行時應用存在繼承關系。我們編寫使用這些類的代碼,忽略基類與派生類之間的類型差異。只要使用基類指針或者引用,基類類型對象、派生類類型對象就可以共享相同的代碼。
3、在泛型編程中,我們所編寫的類和函數能夠多態地用于編譯時不相關的類型。一個類或一個函數可以用來操縱多種類型的對象。
?
參考:
C++ primer 第四版
Effective C++ 3rd
C++編程規范
?
?
總結
以上是生活随笔為你收集整理的从零开始学C++之模板(三):缺省模板参数(借助标准模板容器实现Stack模板)、成员模板、关键字typename...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梦到龙的人多吗
- 下一篇: 【qt】QT 的信号与槽机制