实例解析C++/CLI中的接口与泛型

2016-02-19 20:51 22 1 收藏

今天给大家分享的是由图老师小编精心为您推荐的实例解析C++/CLI中的接口与泛型,喜欢的朋友可以分享一下,也算是给小编一份支持,大家都不容易啊!

【 tulaoshi.com - 编程语言 】

接口
  
  某些时候,让不相关的类分享一组公有成员,以便产生相同的行为,是非常有用的。一个最基本的方法可能是通过一个公共的基类来定义它们,但这种方法太受局限,因为它要求这些类通过继续而互相关联,另外,它们也许还有着各自的基类,且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_castItem^(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()
  {
   arrayint^ ary = gcnew arrayint{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_castint(ie-Current));
   }
   Console::WriteLine();
  } 更多内容请看C/C++应用实例专题,或 泛型
  
  就像函数能用一个或多个类型表示符来定义一样,类型也可以这样来定义。假如有这样一种情况,某种类型建模了一个"数组",其可使用下标来访问每个元素,这样的类型往往被称为"向量",实现一个向量之后,可以保存一组int、一组double、或一组用户自定义类型的元素。然而,正是因为每种类型实现的代码对类型中的元素来说,都是唯一的,因此,可使用泛型机制来定义一个向量类型,并创建特定类型的实例。例10就是这样的一个例子。
  
  例10:
  
  generic typename T
  public ref class Vector
  {
   int length;
   /*1*/ arrayT^ 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 arrayT(Length);
   for (int i = 0; i Length; ++i)
   {
  /*3*/ this[i] = initValue;
   }
   /*4*/ //for each (T element in vector)
   //{
  // element = initValue;
   /

来源:http://www.tulaoshi.com/n/20160219/1624681.html

延伸阅读
01.分析以下程序执行结果 #includeiostream.h int add(int x,int y) { return x+y; } double add(double x,double y) { return x+y; } void main() { int a=4,b=6; double c=2.6,d=7.4; coutadd(a,b)","add(c,d)endl; } 解: 本题说明函数重载的使...
很多初学c#的朋友对于事件与接口感到迷惑不解,不明白它们之间的关系,下面我就用实例来简单的分析讲解一下。 事件,用event修饰符来代表一个事件,我们要创建一个C#事件必须按以下顺序来扫行: 1,创建或标识一个代表。比如下例中的 public delegate void dele(); //声明代表,delegate 关键字通知编译器 dele 是一个委托类...
Microsoft Developer Studio为大多数标准的数据库格式提供了32位ODBC驱动器。这些标准数据格式包括有:SQL Server、Access、Paradox、dBase、FoxPro、Excel、Oracle以及Microsoft Text。如果用户希望使用其他数据格式,则需要安装相应的ODBC驱动器及DBMS。 用户使用自己的DBMS数据库管理功能生成新的数据库模式后,就可以使用ODBC来登录...
一、 什么是VxD 从多任务操作系统Windows 3.1起,计算机中的任一物理设备x可同时被基于Dos或Windows的多个进程使用,这种一对多的关系称为"设备虚拟化",各进程通过运行在核心层的VxD(虚拟x设备驱动程序)存取物理设备x。操作系统提供给用户的软件服务也可以用VxD实现。计算机中的其他资源,如CPU、内存等也可同时被多个进程使用...
现在我们讨论一下新的C++/CLI环境下的一个很酷的特性,称作代理构造函数。 对一个类来说,有多个构造函数是经常的事;并且这多个构造函数有一段共同的代码也很经常。一般地,在这种情况下,我们都是为该共同代码段编写一个独立的函数,然后放在每个构造器中调用。如下例: class Foo { private: int _mem; public: Foo(...

经验教程

36

收藏

57
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部