科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件实例解析C++/CLI中的接口与泛型

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

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

某些时候,让不相关的类分享一组公有成员,以便产生相同的行为,是非常有用的。

作者:谢启东编译 来源:天极开发 2007年11月12日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
 程序在构造函数没有参数的情况下(标号6),分配了一个零元素数组。(注意,指向零元素数组的句柄,不等同于包含nullptr的句柄。)这样做的目的是为了让成员函数可以正常工作,甚至对空Vector也是如此。

  为了完整起见,还定义了一个析构函数,以把句柄设为nullptr,目的是为了显式地告之垃圾回收器,我们对这个对象及与之关联内存的工作已经完成。

  使用在标号8及9中的this[i]还是真有点让人糊涂,那它真正的目的是什么呢?不像等价的模板类,泛型类Vector是在类型T未知的情况下编译为一个程序集,如果编译器不知道T的类型,它也不知道this[i]的类型,因此,它该怎样生成代码,才能把这个表达式转换为Concat所期望的类型呢?其实它不必知道,Concat的其中一个重载版本会要求它的第二个参数为Object^类型,且因为this[i]有类型T,无论类型T是否处在运行时,它都是从System::Object继承来的,因此,它与参数类型相兼容。更进一步来说,因为System::Object有一个名为ToString的虚函数,对此虚函数的调用将产生一个String^,假定类型T已覆盖了这个函数,那么就可返回正确的字符串了。

  函数Equals非常简单明了,但有一件事需要指出,请看标号11,从直觉上来说,我们一般会在此写成!=操作符,但是,这却通不过编译。请记住,类Vector是在对类型T一无所知的情况下编译的,除了它是继承自System::Object,同样地,唯一它允许对T调用的成员函数是那些由System::Object提供的函数,而这些类型未定义!=操作符,幸运的是,它提供了Equals函数,因此可使用它来达到同样的目的;接着,类型T覆盖了这个函数以执行对两个T的相等性判别,例11是主程序。

  例11:

int main()
{
 /*1*/ Vector<int>^ iv1 = gcnew Vector<int>(4);
 /*2*/ Console::WriteLine("iv1: {0}", iv1);
 /*3*/ Vector<int>^ iv2 = gcnew Vector<int>(7, 2);
 Console::WriteLine("iv2: {0}", iv2);
 iv2[1] = 55;
 iv2[3] -= 17;
 iv2[5] *= 3;
 Console::WriteLine("iv2: {0}", iv2);
 /*4*/ Vector<String^>^ sv1 = gcnew Vector<String^>(3);
 Console::WriteLine("sv1: {0}", sv1);
 /*5*/ Vector<String^>^ sv2 = gcnew Vector<String^>(5, "X");
 Console::WriteLine("sv2: {0}", sv2);
 sv2[1] = "AB";
 sv2[3] = String::Concat(sv2[4], "ZZ");
 Console::WriteLine("sv2: {0}", sv2);
 /*6*/ Vector<DateTime>^ dv1 = gcnew Vector<DateTime>(2);
 Console::WriteLine("dv1: {0}", dv1);
 /*7*/ Vector<DateTime>^ dv2 = gcnew Vector<DateTime>(3, DateTime::Now);
 Console::WriteLine("dv2: {0}", dv2);
 for (int i = 0; i < dv2->Length; ++i)
 {
  Thread::Sleep(1100);
  dv2[i] = DateTime::Now;
 }
 Console::WriteLine("dv2: {0}", dv2);
 /*8*/ Vector<Vector<int>^>^ viv = gcnew Vector<Vector<int>^>(3);
 Console::WriteLine("viv: {0}", viv);
 viv[0] = gcnew Vector<int>(2, 1);
 viv[1] = gcnew Vector<int>(4, 2);
 viv[2] = gcnew Vector<int>(3, 5);
 Console::WriteLine("viv: {0}", viv);
 /*9*/ Vector<int>^ iv3 = gcnew Vector<int>(4,3);
 Vector<int>^ iv4 = gcnew Vector<int>(4,3);
 Vector<int>^ iv5 = gcnew Vector<int>(4,2);
 Vector<int>^ iv6 = gcnew Vector<int>(5,6);
 Console::WriteLine("iv3->Equals(iv4) is {0}", iv3->Equals(iv4));
 Console::WriteLine("iv3->Equals(iv5) is {0}", iv3->Equals(iv5));
 Console::WriteLine("iv3->Equals(iv6) is {0}", iv3->Equals(iv6));
}

  为创建Vector的一个特定类型,可在尖括号中作为类型参数指定一个类型,如标号1、3所示。记住,int是值类System::Int32的同义词。(如果泛型有多个类型参数,需要以逗号把它们分隔开。)

  在标号4、5中,定义了一个String^类型的Vector--一个引用类型;在标号6、7中,定义了一个DateTime类型的Vector--一个值类型;在标号8中,定义了一个Vector,而其的元素则为int类型的Vector;最后,用不同的length及Vector int值测试了Equals函数,插1是程序的输出:

  插1:例11的输出

iv1: [0:0:0:0]
iv2: [2:2:2:2:2:2:2]
iv2: [2:55:2:-15:2:6:2]
sv1: [::]
sv2: [X:X:X:X:X]
sv2: [X:AB:X:XZZ:X]
dv1: [1/1/0001 12:00:00 AM:1/1/0001 12:00:00 AM]
dv2: [4/9/2005 3:30:40 PM:4/9/2005 3:30:40 PM:4/9/2005 3:30:40 PM]
dv2: [4/9/2005 3:30:41 PM:4/9/2005 3:30:42 PM:4/9/2005 3:30:43 PM]
viv: [::]
viv: [[1:1]:[2:2:2:2]:[5:5:5]]
iv3->Equals(iv4) is True
iv3->Equals(iv5) is False
iv3->Equals(iv6) is False

  实际上,不但可以定义泛型类,还可以定义泛型接口与代理。

  在前面,也指出了调用泛型成员函数时的一些限制,默认情况下,一个类型参数被限定为从System::Object继承来的任意类型,也就是任意CLI类型。对泛型或函数中的类型参数,如果使用where子句,还可以施加一个或多个限定条件,见例12。

  例12:

generic <typename T>
where T : ValueType
public ref class Vector
{ ... };
value class C {};

/*1*/ Vector<int>^ iv;
/*2*/ Vector<String^>^ sv; //错误
/*3*/ Vector<DateTime>^ dv;
/*4*/ Vector<Vector<int>^>^ viv; //错误
/*5*/ Vector<C>^ cv;

  在本例中,编译器将允许任意有着System::ValueType类型的类型参数,或从它继承来的类型被传递给泛型。假设此时又想定义某种特定的类型,如标号2和3所示,就会出错,因为String与Vector<int>不是值类型。同样地,如果换成例13中的限定条件,那么标号5就会被拒绝,因为值类型C没有实现接口System::IComparable,而System::Int32和System::DateTime却实现了。

  例13:

generic <typename T>
where T : ValueType
public ref class Vector, IComparable
{ ... };

  一旦编译器知道T可以被限定为比System::Object更明确的类型,就会允许调用这些类型中的成员函数,而这些类型则可包含一个基类型或任意顺序、任意数目的接口类型。

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章