面向過程、物件導向、泛型程式設計(Generic Programming,簡稱GP)應該是三種重用的編程方法。傳統的C++語言中,泛型程式設計思想僅僅體現於簡單的模板技術。而之後引入的標準模板庫STL(Standard Template Library)是泛型程式設計思想的實際體現和具體實現。
1. 問題引入
面向過程的方法,可以將常用程式碼片段封裝在一個函數中,然後通過函數調用來達到目標代碼重用的目的。
物件導向的方法,可以通過類的繼承來實現(對象的目標)代碼的重用。
如果需要編寫一個可用於不同資料類型的演算法,可以採用的方法有:
1). 面向過程的方法,對原始碼進行複製和修改,產生不同資料類型版本的演算法函數,調用時需要對資料類型進行手工的判斷;
2). 物件導向的方法,在一個類中,編寫多個同名函數,它們的演算法一致,但是所處理資料的類型不同,當然函數的輸入參數類型也不同,過函數重載來自動調用對應資料類型版本的函數。
顯然, 以上兩種方法都需編寫多個相同演算法的不同函數,不能做到代碼重用。它們二者之間的主要差別,只是調用的方便與否。如果採用泛型程式設計(例如可採用以類型作為參數的傳統C++的模板技術),就可以做到原始碼級的重用:
泛型程式設計方法,編寫以類型作為參數的一個模板函數,在調用時再將參數執行個體化為具體的資料類型。為了實現一個這樣的演算法,在具有不同組織圖(如數組、鏈表、隊列、堆棧等)、含同一類型(如char、int、float、struct S或class C等)的資料或對象的集合(容器)上的,與具體資料類型無關的參數化通用演算法(如排序、檢索、複製、合并等)。只有模版是遠遠不夠的,還需要能夠表示這種集合的容器、能夠在容器中遍曆的迭代器、能夠為演算法和容器實現抽象儲存的分配器、能夠在不同容器之間進行轉換的適配器等等。這些正是泛型程式設計的研究內容,也是STL要實現的目標。
2. 泛型程式設計
泛型(generic)是一種允許一個值取不同資料類型的技術, 而基於此發高效的最抽象表示的編程方法被稱為泛型程式設計(Generic Programming,通用編程/類屬編程)。
泛型程式設計關注於產生通用的軟體組件,讓這些組件在不同的應用場合都能很容易地重用。在C++中,類模板和函數模板是進行泛型程式設計極為有效機制. 與針對問題和資料的物件導向的方法不同,泛型程式設計中強調的是演算法,是一類通用的參數化演算法,它們對各種資料類型和各種資料結構都能以相同的方式進行工作,從而實現原始碼級的軟體重用。
例如,不管(容器)是數組、隊列、鏈表、還是堆棧,不管裡面的元素(類型)是字元、整數、浮點數、還是對象,都可以使用同樣的(迭代器)方法來遍曆容器內的所有元素、擷取指定元素的值、添加或刪除元素,從而實現排序、檢索、複製、合并等各種操作和演算法。
泛型程式設計的通用化演算法,是建立在各種抽象化基礎之上的:利用參數化模版來達到資料類型的抽象化、利用容器和迭代器來達到資料結構的抽象化、利用分配器和適配器來達到儲存分配和介面介面的抽象化。
3. STL
STL(Standard Template Library,標準模板庫)是泛型程式設計思想的實際體現和具體實現,它是一種為泛型組件建立大型標準庫的可擴充架構。STL本身,與物件導向無關,也與具體的程式設計語言無關。 STL的目標是在不損失效率的基礎上進行抽象。這裡的不損失效率,是指盡最大努力來保證其所有的泛型演算法是最優的,並且和手工編碼具有同樣的運行效率。
如果用數學語言來描述,STL的本質就是:不同的資料結構,對應於不同的地址代數結構、以及不同的地址串連方式。從資料結構的一個地址,轉向下一個地址的一些列操作,就對應於迭代器。在資料結構中添加和刪除地址的操作,就對應於容器。
STL將容器看作是結構的泛化,它們都擁有成員,可以描述整體和局部這一現實世界事物的關鍵屬性。STL使用了賦值的演算法,要求採用面向值的語義。STL還假定對容器中的資料和對象,定義了全序。 STL的主要內容是6種組件:容器、泛型演算法、迭代器、函數對象、分配器和適配器等。在標準C++中,STL是作為C++標準庫的一部分而出現的。