泛型程式設計在非C++語言中的實現之探討 (轉)
泛型在非C++語言中的實現之探討
左輕侯
2001.9.22
GP(Generic Programming,泛型程式設計)號稱程式設計思想的又一次革命。但是,在論述GP的資料中,一般都是以C++語言為基礎來討論。那麼,GP是否可以在其它的程式語言中實現呢?這是作者一直在思考的一個問題,因為水平有限和資料匱乏,收穫甚微。現將一些不成熟的想法整理出來,請方家不吝指教。
本文以為例(的情況與此類似,可參照),討論GP的另一種實現思路。程式碼是隨手寫出的,未證。
根據作者的理解,實現GP的關鍵之處,在於實現ADT(Abstract Data Type,抽象資料型別)。只有實現了ADT,才能夠將具體的資料型別與通用的演算法分離開來。
在C++中,ADT的是透過模板來實現的。舉一個最簡單的棧的例子(沒有給出實現部分):
template
public:
void Push(const Type &item);
Type Pop;
...
}
棧的應用:
Stack
int data;
data = 1;
s.Push(data); //入棧
int out;
out = s.Pop; //出棧
透過建立一個int型別的Stack,實現了對int型別資料的儲存。
但是,在Delphi/Java中,並沒有模板這種機制。那麼如何實現ADT呢?與C++不同的是,Delphi/Java的類繼承體系是單根結構的,也就是說,在Delphi中,所有的class都透過強制而保證成為T的子類(Java中是Object)。這個TObject可以看成是一切類的最高層次的抽象。那麼,是否可以認為Delphi/Java中已經先天地提供了對ADT的支援呢?
試著用這種思路建立一個棧:
TStack = class
public
procedure Push(item:TObject);
function Pop:TObject;
...
end;
這個TStack類針對TObject型別的物件進行操作。但是,這個類還不能立即應用,因為在Delphi中,簡單資料型別並不是物件。所以必須再建立一個自定義的資料型別。下面建立了只有一個integer成員的自定義資料型別:
TADT = class
public
data:integer;
end;
再來看棧的應用:
var
stack:TStack;
adt1,adt2:TADT;
begin
stack := TStack.create;
adt1 := TADT.create;
stack.Push(adt1); //入棧
adt2 := stack.Pop as TADT; //出棧
stack.free;
這樣就完成了對ADT物件的儲存。必須注意到,在入棧時,是將adt物件直接入棧的,因為TStack類是對TObject進行操作,由於Delphi的單根結構,可以將任何型別的物件賦給TObject型別的變數。但是,出棧時,返回的也是一個TObject的變數,因此必須用as完成一次向下對映。同樣由於單根結構,Delphi/Java提供了對RTTI的強大支援,因此這種向下對映是輕而易舉的事情。但是,毫無疑問,RTTI在上有所損失。
在實現了ADT的儲存之後,如何才能實現對ADT的操作呢?
在C++中,透過運算子過載來解決這個問題。看一個例子:
在一個List類中,查詢操作:
template
Type* find(Type &value); //查詢指定資料項,找到則返回其地址,否則返回NULL
...
}
template
Type* p = first->link;
where(p!=NULL&&!(p->data==value)){
p=p->link;
}
return p;
}
在List類的find的實現中,程式碼抄自連結串列結構的實現,不需要關心其細節。需要注意的地方只有一個,即判斷條件中的p->data==value。由於p->data和value都是ADT,在建立一個List類的物件時,它們可能是簡單資料,也可以是任何的自定義資料型別。但是,仍然可以統一使用==這樣的運算子,對它們進行操作。為什麼呢?原因在於運算子過載。
下面用一個Point類來說明這一點:
class Point{
private:
int x,y;
public:
int operator ==(const Point &point); //判斷兩個Point物件是否相等
...
}
int Point::operator ==(const Point &point){
if(x==point.x&&y==poing.y){
return 1;
}else{
return 0;
};
}
可以看到,由於過載了==運算子,兩個Point物件之間可以進行比較。同理,任何資料型別,只要過載了相應的運算子,就可以被容器類進行統一的操作。
當目光重新轉向非C++的時候,問題又出現了:Delphi/Java不支援運算子過載。做為補救措施,可以用函式來代替運算子。例如,統一使用equals函式來代替==。可是,更大的問題在於:容器類操作的物件是TObject,而TObject並沒有equals這樣的方法。(在Java中,object有equals方法,但並沒有其它的完整的運算方法。)
在不改變Delphi/Java現有語法的前提下,作者能想到的解決辦法是,建立一個TADT類,作為所有資料結構的基類。TADT中定義了很多象equals、add之類的抽象方法。自定義的資料型別一律從TADT派生,並過載相應方法。而容器類則只需要對TADT進行操作,即可實現通用的演算法了。但是,這種解決方法並不理想。
(補充一點,其實Delphi自己提供了一些通用的容器類,如TList、TCollection、TStack、TQueue等。但與本文中所說的不同,它們儲存的不是TObject,而是pointer。由於Delphi的“引用物件模型”機制,儲存TObject物件,其實也就等於儲存一個pointer,不同之處在於,pointer不但可以儲存物件,而且可以儲存基本資料型別。這應該也是Borland如此設計的原因。但是,這些容器類只提供了add、delete之類的管理方法,並沒有提供通用的演算法,因為對pointer不能進行復雜的操作。實際操作中,往往是員從容器類派生出一個新類,或者在自己的類中維護一個容器類。這也是一種解決辦法,但演算法就不能獨立出來了。)
綜上所述,作者的觀點如下:
1、C++中透過模板機制來實現ADT的儲存,Delphi/Java同樣可以透過單根結構+RTTI的機制來實現。其不同之處在於,C++的實現是語法上的,而Delphi/Java是邏輯上的,也就是說,C++是透過一套特殊的語法來實現的,而Delphi/Java是根據的理論和本身的類庫體系自然地實現的。作者個人以為,從這個角度來看,Delphi/Java的實現機制更加簡單和直觀。
2、從執行效率來算,C++肯定要強於Delphi/Java,因為C++的實現是編譯期的,而Delphi/java是執行期的。RTTI的使用將對效率造成不小的影響。但是,從另一個角度來考慮,ADT在執行期的實現也帶來了好處,那就是可以在執行期隨意地改變容器類所儲存的資料結構型別。作者還沒有考慮過這種“資料型別的多型”會對程式設計帶來什麼實質性的後果。不過大膽地設想一下,以後也許可以將標準演算法封裝在DLL之類已編譯的模組中,甚至封裝在OS提供的COM物件裡,程式設計師只需要建立自己的資料型別,將其提交給相應的介面?……
3、C++中透過運算子過載,來實現對ADT的操作。在不支援運算子過載的Delphi/Java中,作者未能發現好的代替方法。建立統一的ADT抽象類的解決方法,只能說是一個餿主意。:-(有程式設計師傾向於Delphi中應該增加運算子過載,這應該是理由之一,不知道Borland是否重視。另外,據說下一版的Java將會全面支援GP,不知道是透過什麼機制來實現?請了解內幕的高手介紹一下。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-990669/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 在C語言中實現泛型程式設計C語言泛型程式設計
- c++ 泛型程式設計 之 TypeListsC++泛型程式設計
- Kotlin語言中的泛型設計哲學Kotlin泛型
- C語言如何實現泛型程式設計?C語言泛型程式設計
- c++ 泛型 程式設計 之 Functor 設計模式C++泛型程式設計設計模式
- c++ 泛型程式設計 之 自動生成程式碼C++泛型程式設計
- GO語言泛型程式設計實踐Go泛型程式設計
- C++ 簡單實現陣列類泛型程式設計示例C++陣列泛型程式設計
- 關於多型實現Singleton模式的探討 (轉)多型模式
- C#中的介面和泛型集合探討C#泛型
- C++ primer 模板與泛型程式設計C++泛型程式設計
- .NET泛型程式設計簡介 (轉)泛型程式設計
- 泛型程式設計泛型程式設計
- 【譯】在非泛型類中建立泛型方法泛型
- 使用 Go 泛型的函數語言程式設計Go泛型函數程式設計
- C++ 泛型程式設計基礎:模板通識C++泛型程式設計
- hash 表在 go 語言中的實現Go
- java 泛型程式設計Java泛型程式設計
- 泛型最佳實踐:Go泛型設計者教你如何用泛型泛型Go
- [CUJ]泛型程式設計--轉移建構函式 (轉)泛型程式設計函式
- 十、GO程式設計模式 : 泛型程式設計Go程式設計設計模式泛型
- C++程式設計從零開始之語句(轉)C++程式設計
- 用程式碼探討KVC/KVO的實現原理
- 用程式碼探討 KVC/KVO 的實現原理
- c++ 泛型 之 TypeTraintsC++泛型AI
- 再探C++的單件實現 (轉)C++
- C語言/C++程式設計學習:棧的程式碼實現之陣列方案C語言C++程式設計陣列
- C++程式設計實現C++程式設計
- 02. 程式設計核心內功心法之泛型程式設計泛型
- 非技術探討:文章定時釋出功能如何實現
- 深入探討遊戲AI型別及其設計要點遊戲AI型別
- 泛型粒子系統的設計1 (轉)泛型
- 泛型粒子系統的設計2 (轉)泛型
- 泛型粒子系統的設計3 (轉)泛型
- 泛型粒子系統的設計4 (轉)泛型
- 泛型粒子系統的設計5 (轉)泛型
- 泛型粒子系統的設計6 (轉)泛型
- 泛型粒子系統的設計7 (轉)泛型