C++/CLI 提供介面與泛型機制,實現型別安全的多型與演算法複用。本文以集合類別為例完整示範。
介面定義一組抽象成員(隱含 public abstract),不相關類別可實作同一介面,無需共同基底類別(CLI 單一繼承限制)。
public interface class ICollection {
void Put(Object^ o);
Object^ Get();
};
interface class I3 : I1, I2。ref class List : ICollection,需實作所有成員,否須標記 abstract。ref class Queue : ICollection { /* 實作 Put/Get */ };
void ProcessCollection(ICollection^ c) {
Item^ x = gcnew Item();
c->Put(x);
x = static_cast<Item^>(c->Get());
}
List^ myList = gcnew List;
Queue^ myQueue = gcnew Queue;
ProcessCollection(myList);
ProcessCollection(myQueue);
以介面控制代碼分離實作細節。
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); }
};
實作 IEnumerable / IEnumerator 即可支援 for each 迴圈:
array<int>^ ary = gcnew array<int>{10,20,30,40};
for each (int i in ary) Console::Write(" {0}", i);
// 等價於
IEnumerator^ ie = ary->GetEnumerator();
while (ie->MoveNext()) Console::Write(" {0}", (int)ie->Current);
泛型型別定義:generic <typename T> public ref class Vector,於執行期具現化(非編譯期模板),單一組件服務所有型別引數。
array<T>^ vector,索引屬性 property T default[int] 支援 v[i] 語法。T() 取得預設值(值型別為零初始化,參考型別為 nullptr)。for each 迴圈變數為副本,修改不影響原元素,初始化仍需 for 迴圈。ToString() 中 this[i] 隱含裝箱為 Object^,呼叫虛擬 ToString() 達成多型格式化。Equals 無法用 !=(編譯期不知 T 型別),改呼叫虛擬 Equals。generic <typename T>
where T : ValueType
public ref class Vector { ... };
Vector<int>^ iv; // 合法
Vector<DateTime>^ dv; // 合法
Vector<String^>^ sv; // 錯誤:String 非值型別
Vector<Vector<int>^>^ viv; // 錯誤
where 子句支援基底類別與多介面限制,編譯器據此允許呼叫受限成員。
同樣可定義 generic interface class、generic delegate,擴展複用範圍。