国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C++ > 正文

泛型編程在非C++語言中的實現之探討

2019-11-18 18:46:44
字體:
來源:轉載
供稿:網友
GP(Generic PRogramming,泛型編程)號稱編程思想的又一次革命。但是,在論述GP的資料中,一般都是以C++語言為基礎來討論。那么,GP是否可以在其它的編程語言中實現呢?這是作者一直在思考的一個問題,因為水平有限和資料匱乏,收獲甚微。現將一些不成熟的想法整理出來,請方家不吝指教。
  本文以Delphi為例(java的情況與此類似,可參照),討論GP的另一種實現思路。代碼是隨手寫出的,未經驗證。
  根據作者的理解,實現GP的關鍵之處,在于實現ADT(Abstract Data Type,抽象數據類型)。只有實現了ADT,才能夠將具體的數據類型與通用的算法分離開來。
  在C++中,ADT的存儲是通過模板來實現的。舉一個最簡單的棧的例子(沒有給出實現部分):
  
template <class Type> class Stack{
public:
  void Push(const Type &item);
  Type Pop;
  ...
}

  棧的應用:
  
Stack <int> s;
int data;
data = 1;
s.Push(data);  file://入

int out;
out = s.Pop;  file://出

  通過建立一個int類型的Stack對象,實現了對int類型數據的存儲。
  但是,在Delphi/Java中,并沒有模板這種機制。那么如何實現ADT呢?與C++不同的是,Delphi/Java的類繼承體系是單根結構的,也就是說,在Delphi中,所有的class都通過編譯器強制而保證成為TObject的子類(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);  file://入
 
  adt2 := stack.Pop as TADT;  file://出
 
  stack.free;
 
  這樣就完成了對ADT對象的存儲。必須注意到,在入棧時,是將adt對象直接入棧的,因為TStack類是對TObject進行操作,由于Delphi的單根結構,可以將任何類型的對象賦給TObject類型的變量。但是,出棧時,返回的也是一個TObject的變量,因此必須用as完成一次向下映射。同樣由于單根結構,Delphi/Java提供了對RTTI的強大支持,因此這種向下映射是輕而易舉的事情。但是,毫無疑問,RTTI在效率上有所損失。
  在實現了ADT的存儲之后,如何才能實現對ADT的操作呢?
  在C++中,通過運算符重載來解決這個問題。看一個例子:  
  在一個List類中,執行查找操作:
  
template <class Type> class List{
  Type* find(Type &value);  file://查找指定數據項,找到則返回其地址,否則返回NULL
  ...
}

template <class Type> Type* List<Type>::find(Type &value){
  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);  file://判斷兩個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是根據OOP的理論和本身的類庫體系自然地實現的。作者個人以為,從這個角度來看,Delphi/Java的實現機制更加簡單和直觀。
  2、從運行效率來算,C++肯定要強于Delphi/Java,因為C++的實現是編譯期的,而Delphi/java是運行期的。RTTI的使用將對效率造成不小的影響。但是,從另一個角度來考慮,ADT在運行期的實現也帶來了好處,那就是可以在運行期隨意地改變容器類所存儲的數據結構類型。作者還沒有考慮過這種“數據類型的多態”會對編程帶來什么實質性的后果。不過大膽地設想一下,以后也許可以將標準算法封裝在DLL之類已編譯的模塊中,甚至封裝在OS提供的COM對象里,程序員只需要創建自己的數據類型,將其提交給相應的接口?……
  3、C++中通過運算符重載,來實現對ADT的操作。在不支持運算符重載的Delphi/Java中,作者未能發現好的代替方法。建立統一的ADT抽象類的解決方法,只能說是一個餿主意。:-(有程序員傾向于Delphi中應該增加運算符重載,這應該是理由之一,不知道Borland是否重視。另外,據說下一版的Java將會全面支持GP,不知道是通過什么機制來實現?請了解內幕的高手介紹一下。


上一篇:泛型編程在非C++語言中的實現之探討

下一篇:在Delphi與C++之間實現函數與對象共享

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
學習交流
熱門圖片

新聞熱點

疑難解答

圖片精選

網友關注

主站蜘蛛池模板: 炉霍县| 沁阳市| 卓尼县| 萍乡市| 唐海县| 藁城市| 丰城市| 玛沁县| 高雄县| 谷城县| 三亚市| 左云县| 富锦市| 泰宁县| 晋中市| 黄陵县| 泸溪县| 土默特右旗| 青海省| 建阳市| 南投县| 丰城市| 新宁县| 布尔津县| 石嘴山市| 无棣县| 宜宾县| 阿图什市| 古田县| 金川县| 大兴区| 运城市| 阜新| 锦屏县| 阳朔县| 沙坪坝区| 宁远县| 繁昌县| 会理县| 阿克| 上栗县|