程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 實例解析C++/CLI中的接口與泛型

實例解析C++/CLI中的接口與泛型

編輯:C++入門知識
接口
  
  某些時候,讓不相關的類分享一組公有成員,以便產生相同的行為,是非常有用的。一個最基本的方法可能是通過一個公共的基類來定義它們,但這種方法太受局限,因為它要求這些類通過繼續而互相關聯,另外,它們也許還有著各自的基類,且CLI類型只支持單一類繼續。
  
  C++/CLI提供了一種方法,可利用多個類實現一組通用的功能,這就是我們通稱的"接口",而一個接口則是一組成員函數的聲明。要注重,這些函數只是聲明,沒有定義,也就是說,一個接口定義了一個由抽象函數組成的類型--這些函數實際上是純虛函數,且在適當的時候,這些函數由客戶類來實現。一個接口可答應不相關的類用同一名稱和類型,實現同一功能,而無須要求這些類分享公共基類。在例1中演示了怎樣定義一個接口。
  
  例1:
  
   using namespace System;
  public interface class ICollection
  {
   void Put(Object^ o); //隱式public abstract
   Object^ Get(); //隱式public abstract
  };
  一個接口的定義看上去非常像一個類,除了用interface取代了ref或value,所有的函數都沒有函數體,且均隱式為public和abstract。按照通常的約定,一個接口名帶有起始字母I,後再接一個大寫字母。(接口類與接口結構是等價的。)與類相似,一個接口也能有public或private訪問可見性。
  
  一個接口能有一個或多個"基接口",在這種情況下,它將繼續這些接口中的所有抽象函數,例如,在例2中,接口I2顯式繼續自I1,而I3顯式繼續自I1與I2,並通過I2隱式繼續自I1。
  
  例2:
  
   interface class I1 { /* ... */ };
  interface class I2 : I1 { /* ... */ };
  interface class I3 : I1, I2 { /* ... */ };
  一個類可像從基類繼續時那樣,來實現一個接口,見例3。
  
  例3:
  
   public ref class List : ICollection
  {
   public:
  void Put(Object^ o)
  {
   // ...
  }
  Object^ Get()
  {
   // ...
  }
  // ...
  };
  一個類能實現一個以上的接口,在這種情況下,必須使用逗號來分隔接口列表,順序倒不是很重要。當然,一個類在實現一個或多個接口時,也能顯式地帶有一個基類,在這種情況下,基類通常(但不是必須)寫在最前面。
  
  假如一個類實現了一個接口,但沒有定義接口中所有的函數,這個類就必須聲明為abstract。當然了,任何從抽象類繼續而來的類也是抽象類,除非定義了之前的這些抽象函數。 更多內容請看C/C++應用實例專題,或
  接口不提供多重繼續,與此相比,一個CLI類也只能有一個基類,然而,接口卻提供某種與多重類繼續相似的功能,但概念與之完全不同,例如,一個類不能從接口中繼續函數定義;接口繼續體系是獨立於類繼續體系的--實現同一接口的類也許會、但也許不會通過類繼續體系相互關聯。
  
  例4演示了一個類:Queue,其與List無關聯(但除了這個外,兩者都是從Object繼續而來的),兩者都實現了同一接口。
  
  例4:
  
   public ref class Queue : ICollection
  {
   public:
  void Put(Object^ o)
  {
   // ...
  }
  Object^ Get()
  {
   // ...
  }
  // ...
  };
  現在,可用它來編寫處理參數為List或Queue的函數了,如例5。
  
  例5:
  
   ref class Item { /* ... */ };
  void ProcessCollection(ICollection^ c);
  int main()
  {
   List^ myList = gcnew List;
   Queue^ myQueue = gcnew Queue;
   ProcessCollection(myList);
   ProcessCollection(myQueue);
  }
  void ProcessCollection(ICollection^ c)
  {
   Item^ x = gcnew Item();
   /*1*/ c->Put(x);
   /*2*/ x = static_cast<Item^>(c->Get());
  }
  在標號1與2中,為訪問底層的List或Queue,使用了一個指向接口的句柄c,由此,你可傳遞給ProcessCollection一個指向任意對象的句柄,只要它的類實現了這個接口,或者它是從實現了這個接口的類繼續而來的。
  
  例6演示了一個包含只讀屬性X、只寫屬性Y、讀寫屬性Z的接口,對讀寫屬性來說,get與set聲明的順序並不重要。
  
  例6:
  
   public interface class IProperties
  {
   property int X { int get(); }
   property String^ Y { void set(String^ value); }
   property Object^ Z { Object^ get(); void set(Object^ value); }
  };
  一個接口的成員,可以為靜態數據成員、實例或靜態函數、靜態構造函數、實例或靜態屬性、實例或靜態事件、操作符函數、或任意的嵌套類型。
  
  一般來說,我們會用for each語句來枚舉集合中的所有元素,要對集合中的每個元素逐個進行操作,可使用如下語法:
  
   for each (表達式形式的類型標識符)
  嵌入語句
  
  表達式類型必須為一個"集合類型",假如要成為一個集合類型,這個類型必須實現接口System::Collections::IEnumerable,如例7中所定義。
  
  例7:
  
  
   public interface class IEnumerable
  {
   IEnumerator^ GetEnumerator();
  };
  正如大家所見,GetEnumerator返回一個指向IEnumerator的句柄,如例8中所定義。
  
  例8:
  
   public interface class IEnumerator
  {
   bool MoveNext();
   void Reset();
   property Object^ Current { Object^ get(); }
  };
  System::Array為一個集合類型,因為所有的CLI數組類型都繼續自System::Array,所以,任何數組類型表達式都可以作為for each語句中的表達式。在例9的標號1中,for each用於遍歷一個int數組,標號2中的處理過程也一樣,但直接使用了枚舉器。
  
  例9:
  
   using namespace System;
  using namespace System::Collections;
  int main()
  {
   array<int>^ ary = gcnew array<int>{10, 20, 30, 40};
   /*1*/ for each (int i in ary)
   {
  Console::Write(" {0}", i);
   }
   Console::WriteLine();
   /*2*/ IEnumerator^ ie = ary->GetEnumerator();
   while (ie->MoveNext())
   {
  Console::Write(" {0}", static_cast<int>(ie->Current));
   }
   Console::WriteLine();
  } 更多內容請看C/C++應用實例專題,或 泛型
  
  就像函數能用一個或多個類型表示符來定義一樣,類型也可以這樣來定義。假如有這樣一種情況,某種類型建模了一個"數組",其可使用下標來訪問每個元素,這樣的類型往往被稱為"向量",實現一個向量之後,可以保存一組int、一組double、或一組用戶自定義類型的元素。然而,正是因為每種類型實現的代碼對類型中的元素來說,都是唯一的,因此,可使用泛型機制來定義一個向量類型,並創建特定類型的實例。例10就是這樣的一個例子。
  
  例10:
  
   generic <typename T>
  public ref class Vector
  {
   int length;
   /*1*/ array<T>^ vector;
   public:
  property int Length
  {
   int get() { return length; }
   private:
  void set(int value) { length = value; }
  }
  /*2*/ property T default[int]
  {
   T get(int index) { return vector[index]; }
   void set(int index, T value) { vector[index] = value; }
  }
  Vector(int vectorLength, T initValue)
  {
   Length = vectorLength;
   vector = gcnew array<T>(Length);
   for (int i = 0; i < Length; ++i)
   {
  /*3*/ this[i] = initValue;
   }
   /*4*/ //for each (T element in vector)
   //{
  // element = initValue;
   /
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved