




已阅读5页,还剩11页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
教学目标 用函数模板生成相关(重载)函数组 区分函数模板与模板函数 用类模板生成相关类型组 区分类楼板与模板类 了解如何重载模板函数 了解模板、友元、继承与静态成员之间的关系121 简介 本章介绍C+最强大的特性之一 模板。模板使我们可以用一个代码段指定一组相关(重载)函数(称为模板函数)或一组相关类(称为模板类)。 我们可以对数组排序函数编写一个函数模板,然后Cc+自动生成模板函数,可以对int数组、float数组和字符串数组等等进行排序。 第3章介绍了函数模板。如果读者没有阅读该章,则这里再提供一些介绍和例子。 我们可以对堆栈类编写一个类模板,然后让C+自动生成如int、float和string堆栈类的类模板。 注意区分函数摸板与模板函数:函数模板和类模板像是具有各种形状的模板,而模板函数和模板类则相当于按照模板描绘,其形状都是相同的只是画上不同的颜色。 软件工程视点12. 1 模板是C+的软件复用的功能之一。 本章介绍一些函数模板和类模板的例子,并介绍模扳与其他C+特性(如重载、继承、友元和static成员)之间的关系。 这里介绍的模扳机制的设计和细节基于Bjarne Stroustrup的论文Parameterized Types for C+,发表于1988年10月在科罗拉多州丹佛举办的USENIX C+会议上(Proceedings of the USENIX C+ Conference)。 本章只是关于模板问题的简介,第20章“标准模板库(STL)”将深入介绍模板容器类、迭代器和STL算法。第20章有几十个基于摸板的“有生命力的代码”,演示了更复杂的模板编程技术。122 函数模板 重载函数通常是基于不同的数据类型完成类似的操作。如果对每种数据类型的操作是相同的,那么用函数模扳完成这项工作更为简洁和方便。程序员对函数模板的定义只编写一次。基于调用函数时提供的参数类型,C+自动产生单独的目标代码函数来正确地处理每种类型的调用。在C浯言中,这个任务是用预处理指令#define建立的宏完成的(见第17章)。但是,宏可能会产生副作用,并且使编译器不能进行类型检查。函数模板和宏一样的简洁,并且还能让编译器进行全面的类型检查。 测试与调试提示121 函数模板和宏一样允许软件复用。但与宏不同的是,函数模板还可以消除许多类型错误,因为C+提供了安全的全面类型检查。 所有的函数模板定义都是用关键字template开始的,该关键字之后是用尖括号括起来的形式参数表。每一个形式参数之前都有关健字class,例如: template或 template或 template内部类型和自定义类型可用来指定传递给函数的参数类型、函数返回类型和声明函数中变量,函数模板中的形式参数的用法与之类似。该函数定义的方式与定义其他函数类似。注意关键字class指定函数模板类型参数,实际上表示“任何内部类型或用户自定义类型”。 常见编程错误121 函数模板的每个形式类型参数之前不放置关键字class(或新的关键字typename)。 下面看看图121的printArray函数模板,这个函数的用法见图122的完整程序。1 template2 void printArray( const T *array, const int count )3 4 for ( int i = 0; i count; i+ )5 cout array i ;67 cout endl;8 图 12. 1 函数模板 该函数模板把惟一的形式参数T(T一般作为类型参数)声明为函数printArray打印的数组类型。当编译器检测到程序源代码中调用函数printArray时,用printArray的第一个参数的类型替换掉整个模板定义中的T,并建立用来打印指定类型数组的一个完整的模板函数,然后再编译这个新建的函数。图122的程序演示了三个printArray函数,这三个函数分别需要一个int类型的数组、一个double类型的数组和一个char类型的数组。int类型数组的实例函数如下所示: void printArray( const int *array, const int count ) for (int i = O; i count; i+ ) cout array i ; count endl; 模板函数中的每一个形式参数要在函数参数表中至少出现一次。形式参数的名字可以只在模板函数的形式参数表中出现一次。同一个形式参数名可用于多个模板函数。 图122的程序反映了模板函数printArray的用法。程序首先实例化int数组a、double数组b和char数组c,长度分别为5、7、6。然后调用pfintArray打印每个数组,一次用a的第一个参数,类型为int*;一次用b的第一个参数,类型为double*;一次用c的第一个参数,类型为char*。 例如,下列语句: printArray(a,aCount); 使编译器实例化printArray模板函数,类型参数T为int。下列语句: printArray(b,bCount); 使编译器实例化第二个pfintArry模板函数,类型参数T为double。下列语句: printArray(c,cCount); 使编译器实例化第三个printArray模板函数,类型参数T为char。 本例中,模板机制使程序员不必用下列原型编写三个重载函数:void printArray( const int*, const int );void printArray( const double*, const int );void printArray( const char*, const int );1 / Fig 12.2: fig12_02.cpp2 / Using template functions3 #include 45 template6 void printArray( const T *array, const int count )7 8 for (int i = 0; i count; i+ )9 cout array i ;1011 cout endl;121314 int main()15 16 const int aCount = 5, bCount = 7, cCount = 6;17 int a aCount = 1, 2, 3, 4, 5 ;18 double b bCount = 1.1, 2.2, 3.3, 4.4, 6.5, 6.6, 7.7 ;19 char c cCount = HELLO; / 6th position for null2021 cout Array a contains: endl;22 printArray( a, aCount ); / integer template function2324 cout Array b contains: endl;25 printArray( b, bCount ); / double template function2627 cout Array c contains: endl;28 printArray( c, cCount ); / character template function2930 return 0;31 输出结果:Array a contains:1 2 3 4 5Array b contains:1.1 2.2 3.3 4.4 5.5 6.6 7.7Array c contains:H E L L O 图 12.2 使用模板函数 性能提示 12. 1 模板提供了软件复用的好处。请记住,尽管模板只编写一次,但程序中仍然实例化多个模板类的副本。这些副本会占用大量内存。12. 3 重载模板函数模板函数与重载是密切相关的。从函数模板产生的相关函数都是同名的,因此编译器用重载的解决方法调用相应函数。 函数模板本身可以用多种方式重载。我们可以提供其他函数模板,指定不同参数的相同函数名。例如,图122的printArray函数模板可以用另一printArray函数模板重载,用参数lowSubscriPt和highSubscript指定要打印的数组部分(见练习124)。 函数模板也可以用其他非模板函数(同名而参数不同)重载。例如,图121的printArray函数模板可以用一个非模板函数重载,指定以整齐的表格式分栏打印字符串数组(见练习125)。 常见编程错误122 如果使用用户自定义类的类型调用模板,而模板时该类型对象使用=、+、=等运算符,那么这些运算符需要重载。如果不重载这些运算符,则会发生错误,固为编译器在这些函数不存在的情况下仍然调用这些重载的运算符函数。 编译器通过匹配过程确定调用哪个函数。首先,编译器寻找和使用最符合函数名和参数类型的函数调用。如果找不到,则编译器检查是否可以用函数模板产生符合函数名和参数类型的模板函数。 过去,这种与模板的匹配过程要求所有参数类型都完全匹配,而不能进行自动转换。现在已经没有这么严格,可以采用通常的重载规则。 常见编程错误123 编译器通过匹配过程确定调用哪个函数,如果找不到匹配或产生多个匹配,就全产生编译错误。124 类模板 堆栈独立于栈中数据项的类型,这一点不难理解。但是,用程序实现堆栈的时候又必须提供数据类型,这为实现软件的复用性提供了一次很好的机会。所用的方法是描述一个通常意义上的堆栈,然后建立这个类的实例类。所建的实例类虽然是通用类的副本,但是它具有指定的类型。C+的模板类提供了这种功能。 软件工程视点122 类模板通过实例化通用类的特定版本提高了软件的复用性。 为了说明如何定制通用类的模板以形成指定的模板类,模板类需要一种或多种类型参数,所以模板类也常常称为参数化类型。 需要生成多种模板类的程序员只需简单地编写个通用类模板的定义。在需要用模板建立一个新类的时候,程序员只需要用一种简洁的表示方法,编译器就会写出模板类的源代码。例如,堆栈类的模板可以作为编写各种类型堆栈的基础(如float类型、int类型或char类型的堆栈等等)。 图123中的程序定义了Stack(堆栈)的类模板。模板类与通常的类定义没有什么不同,只是以如下所示的首部开头(第8行): template上述首部指出了这是一个类模板的定义,它有一类型参数T(表示所要建立的Stack类的类型)。程序员不需要专门使用标识符T,任何标识符都可以使用。Stack中存储的元素类型在Stack类首部和成员函数定义中一般表示为T。稍后将介绍如何将T与特定类型(如double或id)相关联。I / Fig. 12.3: tstackl.h2 / Class template Stack3 #ifndef TSTACK1_H4 #define TSTACK1 H56 #include 78 template9 class Stack 10 public:1l Stack( int = 10 ); / default constructor (stack size 10)12 Stack() delete stackPtr; / destructor13 bool push( const T& ); / push an element onto the stack14 bool pop( T& ); / pop an element off the stack15 private:16 int size; / # of elements in the stack17 int top; / location of the top element18 T *stackPtr; / pointer to the stack1920 bool isEmpty() const return top = -1; / utility21 bool isFull() const return top = size - 1; / functions22 ;2324 / Constructor with default size 1025 template26 Stack:Stack( int S )27 28 size = S 0 ? S : 10;29 top = -1; / Stack is initially empty30 stackPtr = new T size ; / allocate space for elements31 3233 / Push an element onto the stack34 / return true if successful, false otherwise35 template36 bool Stack:push( const T &pushValue )37 38 if (!isFull() ) 39 stackPtr +top = pushValue; / place item in Stack40 return true; / push successful41 42 return false; / push unsuccessful43 4445 / Pop an element off the stack46 template47 bool Stack:pop( T &popValue )48 49 if (!isEmpty() ) 50 popValue = stackPtr top- ; / remove item from Stack51 return true; / pop successful52 53 return ffalse; / pop unsuccessfu54 5556 #endif57 / Fig. 12.3: fig12_03.cpp58 / Test drive for stack template59 #include 60 #include tstackl.h6162 int main()63 64 Stack doubleStack( 5 );65 double f = 1.1;66 cout Pushing elements onto doubleStackn;6768 while ( doubleStack.push( f ) ) / success true returned69 cout f ;70 f += 1.1;71 7273 coout nStack is full. cannot push f74 nnPopping elements from doubleStackn;7576 while ( doubleStack.pop( f ) ) / success true returned77 cout f ;7879 cout nStack is empty. Cannot popn;8081 Stack intStack;82 int i= 1;83 cout nPushing elements onto intStackn;8485 while ( intStack.push( i ) ) / success true returned86 cout i ;87 +i;88 8990 cout nStack is full. Cannot push i91 nnPopping elements from intStackn;9293 while ( intStack.pop( i ) ) / success true returne94 cout i ;9596 cout nStack is empty. Cannot popn;97 return O;98 输出结果:Pushing elements onto doubleStack1.1 2.2 3.3 4.4 5.5Stack is full. Caunot push 6.6Pepping elements from doubleStack5.5 4.4 3.3 2.2 1.1Stack is empty. Cannot popPushing elements onto intStack1 2 3 4 5 6 7 8 9 10Stack is full. Cannot push 11Popping elements form intStack10 9 8 7 6 5 4 3 2 1Stack is empty. Cannot pop 图12.3 演示类模板 Stack 下面建立一个测试堆栈类模板(见图125的输出)的驱动程序(函数main)。程序在开始的时候实例化了一个大小为5的对象doublestack。该对象声明为类Stack称为double类型的Stack类)的对象。为了产生出double类型的Stack类的源代码,编译器会自动把模板中的参数类型T替换成double。尽管程序看不到这个源代码,但仍将其放进源代码中编译。 然后程序成功地把1.1、2.2、3.3、4.4和5.5这几个double值压入(push)堆栈doubleStack。当试图将第六个值压人堆栈中的时候,push循环中止(栈已经满了,因为它只能容纳5个元素)。 然后程序再将这5个元素弹出(pop)堆栈(以LIFO顺序)。在试图弹出第六个元素的时,出栈循环中止,因为这时堆栈已经空了。 接下来,程序用下面的声明语句实例化了一个int类型的堆栈intStaek: StackintStack因为没有指定堆栈的大小,所以使用默认构造函数(第11行)中的默认值10作为堆栈的大小。重复上述操作,用循环结构不断向intStaek中压入整数值,直到栈满为止,然后再循环从堆栈中弹出数值,直到栈空为止。 在类模板首部以外的成员函数定义都要以下面的形式开头: template然后,成员函数的定义与普通成员函数的定义相似,只是Stack元素的类型要用类型参数T表示。二元作用域运算符和Stack类模板将成员函数的定义与正确的类模板范围联系起来。本例中,类名是Stack。当建立类型为Stack的对象doubleStack的时候,Stack的构造函数使用new建立了一个表示堆栈的double类型数组。因此,对于语句:stackPtr = new T size;编译器将在模板类Stack中生成下面的代码: stackPtr new doublesize; 注意图123函数main中的代码即main上半部分的doubleStack操作和main下半部分的intStaek操作基本相同。这里又可以使用函数模板。图124的程序用函数模板testStack进行与图123相同的工作,将一系列值压入Stack中并从Stack中弹出数值。函数模板testStack用参数T表示Stack中保存的数据类型。该函数模板取4个参数:Stack类型对象的引用、类型为T的值用作压入Stack的第一个值、类型为T的值用作压入Stack的增量值以及const char*类型的字符串表示输出的Stack对象名。函数main只是实例化Stack类型对象doubleStack和实例化Stack类型对象intStaek,如下所示(第37行到第38行): testStack(doubleStack,1.1,1.1,doubleStack); teststack(intStack,1,1,intstack);注意图124的输出与图123的输出一致。1 / Fig. 12.4: fig12_04.cpp2 / Test driver for Stack template.3 / Function main uses a function template to manipulate4 / objects of type Stack.5 #include 6 #include tstack1.h78 / Function template to manipulate Stack9 template10 void testStack(11 Stack &theStack, / reference to the Stack12 T value, / initial value to be pushed13 T increment, / increment for subsequent values14 const char *stackName ) / name of the Stack object15 16 cout nPushing elements onto stackName n;1718 while ( theStack.push( value ) ) / success true returned19 cout value ;20 value += increment;21 2223 cout nStack is full. Cannot push value24 nnPopping elements from stackName n;2526 while ( theStack.pop( value ) / success true returned27 cout value ;2829 cout nStack is empty. Cannot popn;3O 3132 int main()33 34 Stack doubleStack( 5 );35 Stack intStack;3637 testStack( doubleStack, 1.1, 1.1, doubleStack );30 testStack( intStack, 1, 1, intStack );3940 return O;41 输出结果:Pushing elements onto doubleStack1.2 2.2 3.3 4.4 5.5Stack is full. Cannot push 6.6Popping elements from doubleStack5.5 4.4 3.3 2.2 1.1Stack is empty. Cannot popPushing elements onto intStack1 2 3 4 5 6 7 8 9 10Stack is full. Cannot push 11Popping elements form intStack10 9 8 7 6 5 4 3 2 1Stack is empty. Cannot pop 图 12.4 向函数模板传递Stack模板对象125 类模板与无类型参数 上节的Sstack类模扳只用模板首部的类型参数,也可以使用无类型参数(non-type parameter),无类型参数可以有默认参数,一般将无类型参数当作Const处理。例如,模板首都可以取int elements参数,如下所示: template / note non-type parameter然后下列声明: Stackdouble,100) mostRecentSalesFigures; 实例化(在编译时)100个元素的Stack模板类mostRecentSalesFigures(使用double值)。这个模板类的类型为Stack。类的首部可以包含private数据成员,数组声明如下: T stackHolderelements; / array tO hold stack contents 性能提示122 如果可能,在编译时指定容器类(如数组类和堆栈类)的长度(可能通过非类型模板长度参数)可以消除用new动态生成空间的执行时开销。 软件工程视点123 如果可能,在编译时指定容器类的长度(可能通过非典型模板长度参数)以避免new无法取得所要内存时造成致命的造行时错误。 练习中要用无类型参数生成第8章开发的Array类的模板。这个模板可以用编译时指定类型的指定元素个数实例化Array对象,而不必在运行时动态生成Array对象的空间。 不符合常用类模板的特定类型的类可以重定义该类型的类模板。例如,可以用一个Array类模板实例化任何类型的数组。程序员可以控制某个类型Array类的实例化,如Martian,只要建立类名为Array的新类即可。126模板与继承 模板与继承关系如下所示: 类模板可以从模板类派生。 类模板可以从非模板类派生。 模板类可以从类模板派生。 非模板类可以从类模板中派生。127 模板与友元函数和整个类都可以声明为非模板类友元。使用类模板,可以声明各种各样的友元关系。友元可以在类模板与全局函数间、另一个类(可能是模板类)的成员函数间或整个类中(可能是模板类)建立。建立这种友元关系的符号可能很繁琐。 在下列X类的类模板中声明为: templateclass X下列友元声明: friend void f1();使函数f1成为从上述类模板实例化的每个模板类的友元。 在下列X类的类模板中声明为: templateclass X下列友元声明: friend void f2(X 6);对特定类型T(如float)使函数f2(X&)成为X的友元。 在类模板中,可以声明另一个类的成员函数是类模板产生的任何模板类的友元。只要用类名和二元作用域运算符指定其它类的成员函数名。例如,在下列X类的类模板中声明为: templateclass X下列友元声明: friend void A:f4();使A类的成员函数f4成为上述类模板实例化的任何模板类的友元。 在下列X类的类模板中声明为: templateclass X下列友元声明: friend void C:f5( X & ); 对特定类型T(如float)使成员函数: C:f5( X & );成为X模板类的友元函数。 在下列X类的类模板中声明为: templateClass X 可以声明第二个类Y,如下所示: friend class Y; 使Y类的每个成员函数成为X的类模板产生的每个模板类的友元。 在下列X类的类模板中声明为: templateclass X 可以声明第二个类Z,如下所示: friend class Z; 使模板类用特定类型T(如float)实例化时,class Z的所有成员成为模板类X的友元。128 模板与static成员 在非模板类中,类的所有对象共享一个static数据成员,Static数据成员应在文件范围内初始化。 从类模板实例化的每个模板类有自己的类模板static数据成员,该模板类的所有对象共享一个Static数据成员。和非模板类的static数据成员一样,模板类的static数据成员也应在文件范围内初始化。每个模板类有自己的类摸板的static数据成员副本。小 结 模板使我们可以用一个代码段指定一组相关函数(称为模板函数)或一组相关类(称为模板类)。 程序员对函数模板的定义只编写一次。基于调用函数时提供的参数类型,C+自动产生单独的函数来正确地处理每种类型的调用。这些都是利用程序源代码的剩余空间进行编译。 所有函数模板定义都足用关键字template开始的,该关键字之后是用尖括号括起来的形式参数表。函数模板的每个形式类型参数之前应有关键字class(或新的关键字typename)。关键字class指定函数模板的类型参数,实际上表示“任何内部类型或用户自定义类型”。 模板定义的形式参数可用来指定传递给函数的参数类型、函数返回类型和声明函数中变量。 形式参数的名字可以只在模板的形式参数表中出现一次。同一个形式参数名可用于多个模板函数。 函数模板本身可以用多种方式重载。我们可以提供其他函数模板,指定不同参数的相同函数名。函数模板也可以用其他非模板函数(同名而不同参数)重载。 类模板提供了描述一个类和实例化类(即该通用类指定类型的版本)的方法。 为了说明如何定制通用类模板以形成指定的模板类,类模板需要类型参数,所以类模板也常常称为参数化类型。 要使用模板类的程序员只需简单地编写一个类模板。在需要用模板建立一个新的指定类型的类时,程序员只需要用一种简洁的表示方法,编译器就会写出该模板类的源代码。 类模板的定义似乎与普通的类定义没什么不同,除了使用template指明这是一个带类型参数T(指明创建的类的类型)的类模板定义。在类首部和成员函数的定义中,类型 作为一个通用的类型名。 在类模板首部以外的成员函数定义都要以template开头。接着,成员函数的定义与普通成员函数的定义相似,只是类中的数据通常用类型参数T表示。二元作用域运算符总是把成员函数的定义与正确的类范围联系起来。 类模板首部也可以使用无类型参数。 特定类型的类可以重定义该类型的类模板。 类模板可以从模板类派生。类模板可以从非模板类派生。模板类可以从类模板派生。非模板类可以从类模板中派生。 函数和整个类都可以声明为非模板类的友元。使用类模板,可以声明各种各样的友元关系。 友元可以在类模板与全局函数间、另一个类(可能是模板类)的成员函数间或整个类中(可能是模板类)建立。 从类模板实例化的每个模板类有自己的类模板的Static数据成员该模板类的所有对象共享一个static数据成员。和非模板类的static数据成员一样,模板类的Static数据成员也应在文件范围内初始化。 每个模板类有该类模板的static数据成员副本。术 语angle brackets 尖括号 keyword temPlate 关键字templateclass template 类模板 non-type parameter in a templateheader模板首class template name 类模板名 部中的无类型参数formal parameter in a template header 模 overloading a template function 重载模板函数 板首部中的形式参数parameterized type 参数化类型friend of a template 模板的友元 static data member of a class template function template 函数模板 类模板的static 数据成员function temPlate declaration 函数模板的声明 static data member of a template class 模function template definition 函数模扳的定义 板类的static数据成员keyworde class in a template type parameter 模板 static member function of a class template 类型参数中的关键字class 类模板的static成员函数static member function of a template class 模板类template argument 模板实参 的static成员函数 template name 模板名template class 模板类 template parameter 模板形参template class member function 模板类成员函数 type parameter in a template header 模板template 类型参数 首部的template function 模板函数 typename自测练习12.1 判断下列各题是否正确。如果不正确,请说明原因。 a)函数模板的友元函数必须是模板函数。 b)如果从一个带单个static数据成员的类模板产生几个模板类,则每个模板类共享类模板static数据成员的一个副本。 c)模板函数可以用同名的另一模板函数重载。 d)形式参数的名字可以只在模板函数的形式参数表中出现一次。同一个形式参数名只能用于一个模板函数。 e)关键字class指定函数模板类型参数,实际上表示“任何用户自定义类型”。122填空: a)模板使我们可以用一个代码段指定一组相关函数(称为)或一组相关类(称 )。 b)所有的函数模板定义都是以关键字开始的,该关键字之后是用括起 来的形式参数表。 c)从一个函数模板产生的相关函数都同名,因此编译器用的解决方法调用相应 函数。 d)类模板也称为类型。 e)运算符和模板类名一起将每个成员函数定义与类模板的范围相关联。 f)和非模板类的static数据成员一样,模板类的static数据成员也应在范围 内初始化。自测练习答案121 a)不正确。也可以用非模板函数。 b)不正确。每个模板类有自己的静态数据成员副本。 c)正确。 d)不正确。模板函数间的形式参数名不必惟一。 e)不正确。这里的关键字class也允许内部类型的参数类型。 122 a)模板函数、模板类。 b)template、尖括号()。 c)重载。 d)参数化。 e)二元作用域。 f)文件。练 习 123 根据图515的
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 水库设备更新改造工程节能评估报告
- 音乐分析考试试题及答案
- 选煤厂电工考试题及答案
- 水库扩建工程节能评估报告
- 低品位铁精粉提纯项目技术方案
- 智能叉车自动化控制方案
- 电子薄膜生产线项目建筑工程方案
- 智算中心能源管理与节能优化方案
- 离婚后子女探望权及费用支付补充合同
- 知识产权贯标认证辅导与知识产权评估合同
- 2025年中国搬家公司行业市场运行动态及投资发展潜力分析报告
- 油脂脂肪酸组成的测定内标法58课件
- 光存储技术革新-洞察及研究
- 浙江科技大学《高等数学Ⅱ》2025-2026学年期末试卷(A卷)
- 13 唐诗五首《钱塘湖春行》课件
- 电影鉴赏教学课件
- 跨境贸易背景下非遗工艺产业的机遇与挑战
- (高清版)DB11∕T 2456-2025 消防安全管理人员能力评价规范
- 胎心监护及并发症处理
- 2025至2030苯基吡唑类杀虫剂行业市场发展分析及发展前景报告
- 老年病贫血护理
评论
0/150
提交评论