第10章 类型参数化——泛型
课后答案——C++语言程序设计教程(第二版)

1.1习题1解答1.(1)机器语言是计算机直接理解执行的语言,由一系列(二进制)指令组成,其助记符构成了汇编语言;接近人的自然语言习惯的程序设计语言为高级语言。
(2)结构化程序设计方法主要内容有:自顶向下,逐步求精;面向对象方法将现实世界中的客观事物描述成具有属性和行为的对象,抽象出共同属性和行为,形成类。
(3)C++程序开发通常要经过5个阶段,包括:编辑,编译,连接,运行,调试。
首先是编辑阶段,任务是编辑源程序,C++源程序文件通常带有.c p p扩展名。
接着,使用编译器对源程序进行编译,将源程序翻译为机器语言代码(目标代码),过程分为词法分析、语法分析、代码生成3个步骤。
在此之前,预编译器会自动执行源程序中的预处理指令,完成将其他源程序文件包括到要编译的文件中,以及执行各种文字替换等。
连接器的功能就是将目标代码同缺失函数的代码连接起来,将这个“漏洞”补上,生成可执行文件。
程序运行时,可执行文件由操作系统装入内存,然后CPU从内存中取出程序执行。
若程序运行进程中出现了错误,还在需要对程序进行调试。
(4)对象与对象之间通过消息进行相互通信。
(5)类是具有相同属性和行为的一组对象的抽象;任何一个对象都是某个类的一个实例。
(6)多态性是指在一般类中定义的属性或行为,被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。
(7)面向对象的软件开发过程主要包括面向对象的方法分析、面向对象的设计、面向对象的编程、面向对象的测试和面向对象的维护。
(8)泛型程序设计是指在程序设计时,将数据类型参数化,编写具有通用性和可重用的程序。
(9)#include<iostream>是一条预处理指令(语句),在编译(或预处理)时由编译器(或预编译器)执行,其功能是将iostream文件包含(复制)到指令处。
(10)C++中使用cin作为标准输入流对象,通常代表键盘,与提取操作符>>连用;使用cout作为标准输出流对象,通常代表显示设备,与<<连用。
C#期末复习要点

1程序控制结构,特别是异常:(1)异常(Exception)——程序检测到的运行时刻不正常的情况。
如被0 除、数组越界访问或空闲存储内存耗尽等等。
(2)异常处理——是一种允许两个独立开发的程序组件在程序执行期间遇到程序不正常的情况时相互通信的机制。
(3)这里的异常是指软件异常(4)抛掷异常的程序段……throw 表达式;(异常抛出)……(5)捕获并处理异常的程序段try复合语句(保护段)catch(异常类型声明)复合语句(处理段)catch(异常类型声明)复合语句(处理段)……(6)异常处理的执行过程如下:①程序通过正常的顺序执行到达try语句,然后执行try块内的保护段。
②如果在保护段执行期间没有引起异常,那么跟在try块后的catch语句就不执行,程序从最后一个catch语句后面的语句继续执行下去。
③如果在保护段执行期间或在保护段调用的任何函数中(直接或间接的调用)有异常被抛掷,则从通过throw创建的对象中创建一个异常对象(隐含调用拷贝构造函数),程序转到catch处理段。
④如果匹配的catch处理器未找到,则terminate()将被自动调用,该函数的默认功能是调用abort终止程序。
⑤如果找到了一个匹配的catch处理程序,且它通过值进行捕获,则其形参通过拷贝异常对象进行初始化。
在形参被初始化之后,“展开栈”的过程开始。
这包括对那些在与catch处理器相对应的try块开始和异常丢弃地点之间创建的(但尚未析构的)所有局部对象的析构。
3.委托的使用:答:(1)委托定义;(2)用委托声明变量;(3)准备委托函数;(4)委托调用;(5)委托赋值。
4 this指针或引用:(1)面向对象语言提供的一个特殊对象指针,this指针是一种隐含指针,每个非静态的成员函数都有一个this指针,用来标记成员函数操作哪个对象的数据成员。
(2)this是为了实现代码共享,C++和C一样:函数的作用是减少代码开销。
java泛型函数定义

java泛型函数定义Java泛型函数定义是指在函数声明中使用泛型类型参数来定义一个通用的函数。
泛型函数可以接受不同类型的参数,并返回不同类型的结果。
泛型函数定义的语法如下:```public <T> T functionName(T parameter) {//函数体}```其中,`<T>`指定了一个泛型类型参数T,T可以是任何类型,包括基本类型和对象类型。
泛型函数可以使用泛型类型参数T作为参数类型或返回类型。
例如,下面的代码定义了一个泛型函数`max`,用于比较两个参数的大小并返回较大的那个:```public static <T extends Comparable<T>> T max(T x, T y) { if (pareTo(y) > 0) {return x;} else {return y;}}```其中,`<T extends Comparable<T>>`指定了泛型类型参数T必须是实现了`Comparable`接口的类型。
这样,我们就可以使用`compareTo`方法来比较两个参数的大小了。
使用泛型函数的时候,可以根据需要传入不同类型的参数,函数会自动根据传入的参数类型推导出泛型类型参数T的类型。
例如: ```Integer x = 1;Integer y = 2;Integer z = max(x, y); // z = 2String s1 = 'hello';String s2 = 'world';String s3 = max(s1, s2); // s3 = 'world'```在泛型函数中,我们也可以使用多个泛型类型参数,并且它们可以有不同的类型。
例如:```public static <T, U> boolean isEqual(T x, U y) {return x.equals(y);}```这个函数可以接受任意类型的参数,并判断它们是否相等。
C#中的泛型和泛型集合

C#中的泛型和泛型集合⼀、什么是泛型?泛型是C#语⾔和公共语⾔运⾏库(CLR)中的⼀个新功能,它将类型参数的概念引⼊.NET Framework。
类型参数使得设计某些类和⽅法成为可能,例如,通过使⽤泛型类型参数T,可以⼤⼤简化类型之间的强制转换或装箱操作的过程(下⼀篇将说明如何解决装箱、拆箱问题)。
说⽩了,泛型就是通过参数化类型来实现在同⼀份代码上操作多种数据类型,利⽤“参数化类型”将类型抽象化,从⽽实现灵活的复⽤。
使⽤泛型给代码带来的5点好处:1、可以做⼤限度的重⽤代码、保护类型的安全以及提⾼性能。
2、可以创建集合类。
3、可以创建⾃⼰的泛型接⼝、泛型⽅法、泛型类、泛型事件和泛型委托。
4、可以对泛型类进⾏约束,以访问特定数据类型的⽅法。
5、关于泛型数据类型中使⽤的类型的信息,可在运⾏时通过反射获取。
例⼦:using System;namespace ConsoleApp{class Program{class Test<T>{public T obj;public Test(T obj){this.obj = obj;}}static void Main(string[] args){int obj1 = 2;var test = new Test<int>(obj1);Console.WriteLine("int:" + test.obj);string obj2 = "hello world";var test1 = new Test<string>(obj2);Console.WriteLine("String:" + test1.obj);Console.ReadKey();}}} 输出结果是: int:2 String:hello world 分析: 1、 Test是⼀个泛型类。
C#之使类型参数--泛型

C#之使类型参数--泛型1、泛型是什么泛型的就是“通⽤类型”,它可以代替任何的数据类型,使类型参数化,从⽽达到只实现⼀个⽅法就可以操作多种数据类型的⽬的。
2、为什么使⽤泛型举⼀个⽐较两个数⼤⼩的例⼦:以上例⼦实现int类型数据的⼤⼩⽐较是完全没有问题的,但是如果客户现在增加需求“⼜可以实现两个字符串⼤⼩的⽐较”,此时就不得不在类中再添加⼀个⽐较字符串⼤⼩的⽅法了:如果客户现在还增加需求,要求实现浮点型的⽐较,那么⼯作量就更⼤了,不得不再次修改代码,显然这不是我们想看到的,两个⽅法中有⼤部分代码是类似的,所以微软提出了⼀个激动⼈⼼的特性--泛型,他使得类型可以被参数化。
where语句是类型参数的约束它⽤来使参数可以适⽤于CompareTo⽅法。
向泛型中加⼊元素的效率远⽐⾮泛型数组⾼,原因是⾮泛型rrayList的Add(Object value)⽅法中,参数为object类型,当把int参数i传⼊⽅法时,会发⽣装箱操作,从⽽导致性能的损失,使运⾏的时间变得更长。
泛型可以保证类型安全,当你向int类型数组中添加string类型的值的时候,会造成“⽆法从string类型转换为int类型”的错误,因为你⽤int类型初始化了泛型类型。
3、泛型参数解析1、类型参数根据泛型类型参数是否已经提供实际类型,可分为未绑定的泛型和已构造的泛型,如果没有给泛型提供实际类型,此时的泛型成为未绑定的泛型;如果已指定了实际类型作为参数,此时的泛型成为已构造泛型。
已构造泛型⼜称为开放泛型和密封泛型。
开放泛型指包含类型参数的泛型,所有未绑定的类型都属于开放类型;⽽封闭类型指已经为每个参数都指定了实际数据类型的泛型。
2、泛型中的静态字段和静态函数问题对于⾮泛型类,定义了⼀个静态字段,不管是创建了多少个该类的实例,也不管从该类派⽣出多少个实例,都只存在⼀个字段,但是每个封闭的泛型类型中都有仅属于他⾃⼰的静态字段。
这是因为,在使⽤实际类型参数代替泛型参数时,编译器会根据不同的类型参数,从新⽣成类型。
ts 泛型类型 默认值 理解

ts 泛型类型默认值理解全文共四篇示例,供读者参考第一篇示例:TS的泛型类型是一种非常强大和有用的特性,它使得我们能够以一种更加灵活和通用的方式来定义函数和类。
泛型类型允许我们在定义函数或类的时候不指定具体的类型,而是使用一个占位符来表示该类型。
这样一来,我们就可以在使用函数或类的时候再指定具体的类型,从而实现更加灵活和通用的代码编写。
在实际的项目中,我们经常会遇到需要定义泛型类型并给其设置默认值的情况。
默认值是一种在定义泛型类型时设置的初始值,当我们在使用泛型类型的时候不显式地指定具体的类型时,就会使用默认值来作为该泛型类型的类型。
在TS中给泛型类型设置默认值非常简单,在定义泛型类型的时候可以使用`=`符号来指定默认值。
例如:```typescriptfunction identity<T = string>(arg: T): T {return arg;}const output = identity<number>(10); // output 的类型为numberconst output2 = identity('hello'); // output2 的类型为string```上面的例子中,我们定义了一个泛型函数`identity`,并且为泛型类型`T`设置了默认值`string`。
当我们在使用`identity`函数时没有显式地指定`T`的类型时,TS会自动推断泛型类型为`string`,从而返回值的类型也会是`string`。
通过设置默认值,我们可以在定义泛型类型的时候为其指定一个普适的类型,当我们在使用这个泛型类型时不做额外的指定时,就会使用默认值。
这样一来,可以简化代码的编写,并且提高代码的复用性和可维护性。
TS的泛型类型和默认值是一种非常实用的特性,能够帮助我们更加灵活和通用地定义函数和类。
通过设置默认值,可以简化代码的编写,并提高代码的复用性和可维护性。
C#泛型

目录1. 泛型简介 (2)1.1.理解泛型 (2)1.2.泛型简介 (3)2.泛型的优点 (3)3.泛型类型参数 (4)4.类型参数的约束 (5)5.泛型类 (9)6.泛型接口 (11)7.泛型方法 (13)8.泛型委托 (15)9.泛型代码中的默认关键字 (17)10.泛型和属性 (18)1.泛型简介1.1.理解泛型如果我们编写一个求和的函数,我们应该怎么做?如果这两个数是整数,我们可以实现下面的函数:如果求两个double类型的数的和,我们还可以用重载实现:假设程序升级需要支持,decimal、long等类型的加法操作,我们怎么办?用重载去一次实现这些函数?可不可写一个通用的函数呢?于是我们想到object类型,实现了下面的函数:这里用到的技术就是装箱和拆箱,Add方法首先将所有数据类型的数据进行装箱,这样就统一了它们的类型,然后再进行类型转换和计算,计算结果再拆箱就是要求的结果。
实际上就是“泛型”思想的一个应用,这里用一个通用方法解决了几乎任何数值类型两个数的求和操作。
可以说,对于这个求和算法来讲是通用的、泛型的(不需要特定数据类型)。
但是我们从上面的代码可以看到问题,就是它频繁的执行装箱和拆箱操作,这些操作是非常损耗性能的。
另外,装箱和拆箱的代码也显得比较“难看”,因为每次都要进行强类型转换,有没有更好的方式来编写这种通用算法呢?于是,C#从 2.0版本开始引入了泛型技术,泛型能够给我们带来的两个明显好处是代码清晰并且减少了装箱、拆箱。
1.2.泛型简介下面我们应用泛型实现交换两个数的例子:这个交换算法不仅支持任何数字类型,它还支持你在程序中能用到得任何类型。
注意,泛型不属于任何命名空间,准确的讲,泛型是一种编译技术。
在书写算法的时候,泛型技术允许我们使用一种类型占位符(或称之为类型参数,这里使用的占位符是“T”)作为类型的标识符,而不需要指定特定类型。
当我们在调用这个算法的时候,编译器使用指定的类型代替类型占位符建立一个针对这种类型的算法。
java+泛型

浅谈Java泛型编程原文地址:/thread.jspa?messageID=154504我原本想全文翻译Generics in the Java Programming Language,但是功力不够,太耗时间。
于是乎按照原文的框架,翻了一些再加上自己写的一点东西。
第一次写文,如有谬误还清指出~~谢谢!浅谈Java泛型编程1 引言在JDK 1.5中,几个新的特征被引入Java语言。
其中之一就是泛型(generics)。
泛型(generics,genericity)又称为“参数类型化(parameterized type)”或“模板(templates)”,是和继承(inheritance)不同而互补的一种组件复用机制。
继承和泛型的不同之处在于——在一个系统中,继承层次是垂直方向,从抽象到具体,而泛型是水平方向上的。
当运用继承,不同的类型将拥有相同的接口,并获得了多态性;当运用泛型,将拥有许多不同的类型,并得以相同的算法作用在它们身上。
因此,一般说来,当类型与实现方法无关时,使用泛型;否则,用继承。
泛型技术最直接联想到的用途就是建立容器类型。
下面是一个没有使用泛型技术的例子:List myIntList = new LinkedList();// 1myIntLikst.add(new Integer(0));// 2Integer x = (Integer)myIntList.iterator().next();// 3显然,程序员知道究竟是什么具体类型被放进了myIntList中。
但是,第3行的类型转换(cast)是必不可少的。
因为编译器仅仅能保证iterator返回的是Object类型。
要想保证将这个值传给一个Integer类型变量是安全的,就必须类型转换。
除了使代码显得有些混乱外,类型转换更带来了运行时错误的可能性。
因为程序员难免会犯错误。
使用了泛型技术,程序员就可以确切地表达他们的意图,并且把myIntList限制为包含一种具体类型。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
where T:U
10.4.2 类型参数约束
注意,在CLR 2.0中,只能为默认构造函数定义约束, 不能为其他构造函数定义约束。 之所以要使用类型参数约束是因为,如果要检查泛型列 表中的某个项以确定它是否有效,或者将它与其他某个 项进行比较,则编译器必须在一定程度上保证它需要调 用的运算符或方法能够受到客户端代码可能指定的任何 类型参数的支持。这种保证是通过对泛型类定义应用一 个或多个约束获得的。例如,基类约束告知编译器,仅 此类型的对象或由此类型派生的对象才可用作类型参数。 一旦编译器拥有该保证,它就能够允许在泛型类中调用 该类型的方法。
10.4.1 默认关键字
【例10-4】default关键字演示 public class GenericList<T> { public T GetNext() { T temp = default(T);//使用default关键字来给temp初始化 Node current = head; if (current != null) { temp = current.Data; current = current.Next; } return temp; } }
可以考虑以T作为具有单个字母类型参数的类型的类型参数名, 例如下列代码。
public int IComparer<T>() { return 0; } public delegate bool Predicate<T>(T item);//定义了一个泛型委托 public struct Nullable<T> where T : struct { /*...*/ }//使用泛型约束, 参见10.4.2节
10.4.2 类型参数约束
通过约束类型参数,对于约束类型及其继承层次结 构中的所有类型,可以增加所支持的操作和方法调 用的数量。因此在设计泛型类或方法时,如果需要 对泛型成员执行任意操作(除简单赋值之外),或 调用System.Object不支持的任意方法,需要对该 类型参数应用约束。 在应用where T:class约束时,应避免对类型参数 使用运算符“==”和“!=”,因为这些运算符仅能 够测试引用同一性而无法测试值相等性。即使在用 作参数的类型中重载这些运算符时,也是如此。
class program { public static void Main() { Node<int> MyNode = new Node<int>(); //省略其他代码 } }
10.2.2 常用的泛型集合类
泛型集合类 List<> Dictionary<> 非泛型集合类 ArrayList Hashtable 泛型举例 List<string> dinosaurs=new List<string>();
10.1.3 泛型的参数命名准则
务必使用具有描述性的名称为泛型类型参数命名,除非单个字母 的名称即可表示其含义,而描述性名称不会包含更多含义。
public interface ISessionChannel<TSession> { /*...*/ } public delegate TOutput Converter<TInput, TOutput>(TInput from); public class List<T> { /*...*/ }
其中,尖括号中是类型参数列表,类型参数列表可以由多个类型参数构成, 多个类型参数之间用逗号隔开。类型只是占位符,一般使用大写的“T”、U”、 “V”等作为类型参数。
例如: class Node<T> { private T data; public Node<T> next; //省略其他代码 }
Queue<>
Queue
Stack<>
Stack
SortedList<>
SortdList
10.3 泛型方法
泛型方法是使用类型参数声明的方法。定义泛型方法的 语法形式如下。
static void Swap<T>(ref T lhs, ref T rhs) { T temp; temp = lhs; lhs = rhs; rhs = temp; }
章节内容
10.1 泛型概述
10.2 泛型类
10.3 泛型方法
10.4 泛型类的特性
10.5 小结
10.1.1 泛型的概念
泛型是对CLR类型系统的一种扩展,用于定义某些细节 未指定的类型,通过参数化类型来实现在同一段代码上 操作多种数据类型。
10.1.2 泛型的优点
1.性能 2.类型安全性 3.二进制代码的重用 4.代码的扩展
约束 where T:struct 说明 使用结构约束,类型T必须是值类型 类约束指定,类型T必须是引用类型,用于任何类、接 口、委托或数组类型
where T:class
类型参数必须是指定的基类或派生自指定的基类, where T:基类名 where T:Foo表示为T指定的类必须是Foo类或这个类的派 如where T:Foo 生类
10.3 泛型方法
下列代码演示一种使用int作为类型参数的方法调用方 式。
static void TestSwap() { int a = 1; int b = 2; Swap<int>(ref a, ref b); System.Console.WriteLine(a + " " + b); }
where T:接口名 类型参数必须是指定的接口或实现指定的接口,可以指 称 定多个接口约束,where T:IFoo指定类型T必须实现接口 IFoo 如where T:IFoo where T:new() 是一个构造函数约束,指定类型T必须有一个无参数的 公共构造函数,与其他约束一起使用时,new()约束必须 最后指定 为T提供的类型参数必须是为U提供的参数,或派生自为 U提供的参数,该约束也称为裸类型约束
10.2.1 泛型类的定义与实例化
在实例化泛型类时,需要使用具体的类型(如int、double、 string或者一个自定义类等)来代替类型参数,这样就可以在 实例化泛型类时指定不同类型,生成具有不同类型的实例。 泛型类的实例化语法形式如下: 类名<类型参数列表> 实例名 = new 类名<类型参数列表>([构造 函数的实参]); 对于上面定义的泛型类Node,实例化时的代码如下。
10.4.1 默认关键字
在泛型类和泛型方法中会产生一个问题,在如下 情况未知时,如何将默认值分配给参数化类型T?
T是引用类型还是值类型。 如果T为值类型,则它是数值还是结构。
给定参数类型T的一个变量t,只有当T为引用类型 时,语句t = null才会有效;只有当T为数值类型 而不是结构时,语句t=0才会有效。 解决方案为,使用default关键字。
第10章 类型参数化——泛型
泛型(Generic)是CLR 2.0相对于CLR 1.0新增的一个特 性。在此前的CLR 1.0中,如果要创建一个灵活的类或方 法,并且该类或方法需要在代码编译后才能确定类型,那 么就必须以Object类为基础。但是Object类在编译期间 是无法保证类型安全的,这是因为任何类型都可以转换为 Object类。然而Object类转换为其他类型都将使用强制 类型转换的方法,这就容易造成类型转换错误,且将值类 型转换为Object类会为造成性能损失。 针对上述问题,CLR 2.0提供了泛型。有了泛型,就不需 要使用Object类了。泛型类可以根据需要,使用特定类型 替换泛型类型,从而保证了类型安全性。当某个类型不支 持泛型类时,编译器就会生成错误代码。
10.4.2 类型参数约束
public class Myclass<T> where T:IFoo,new()
可以对多个参数应用约束,并对一个参数应用多个约束, 例如下列代码。
10.4.2 类型参数约束
【例10-5】值类型约束演示
struct Point { private int x; private int y; public Point(int a, int b) { x = a; y = b; } }
StaticDemo<string>.x=4; StaticDemo<int>.x=5; Console.WriteLine(StaticDemo<string>.x); Console.WriteLine(StaticDemo<int>.x);
//输出4 //输出5
10.5 小结
本章主要介绍了CLR 2.0中的一个非常重要的特 性——泛型。通过泛型可以创建独立于类型的类、 方法、结构和委托等。通过泛型可以解决.NET 1.0 和.NET 1.1中困扰开发人员的编译器错位和代码冗 余等问题,避免了对于数据类型的频繁强制转换和 装箱、拆箱,实现了代码重用、类型安全和高性能。 泛型类最常用于集合,如链接列表、哈希表、堆栈、 队列和树等。诸如从集合中添加或移除项之类的操 作都能够以大致相同的方式执行,与所存储数据的 类型无关。对于大多数需要集合类的方案,建议使 用.NET Framework类库中所提供的类。
通常将“T”作为描述性类型参数名的前缀,代码如下。
public interface ISessionChannel<TSession> { TSession Session { get; } }
10.2.1 泛型类的定义与实例化
定义泛型类的语法形式如下: 访问修饰符] class类名<类型参数列表> { 类体 }
Dictionary<string,string>openWith = new Dictionary<string,string>(); openWith.Add("txt", "notepad.exe");