副标题#e#
接口
某些时候,让不相关的类分享一组公有成员,以便发生沟通的行为,长短常有用的。一个最根基的要领大概是通过一个民众的基类来界说它们,但这种要领太受范围,因为它要求这些类通过担任而相互关联,别的,它们也许尚有着各自的基类,且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。虽然了,任何从抽象类担任而来的类也是抽象类,除非界说了之前的这些抽象函数。
接口不提供多重担任,与此对比,一个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());
}
#p#副标题#e#
在标号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(); }
};
#p#分页标题#e#
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();
}
泛型
就像函数能用一个或多个范例暗示符来界说一样,范例也可以这样来界说。如果有这样一种环境,某种范例建模了一个"数组",其可利用下标来会见每个元素,这样的范例往往被称为"向量",实现一个向量之后,可以生存一组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;
/