《类和对象二.ppt》由会员分享,可在线阅读,更多相关《类和对象二.ppt(90页珍藏版)》请在三一文库上搜索。
1、在定义类时不能对成员变量进行初始化,因为无法确定成员变量属于哪一个对象。 成员变量一般都定义为私有属性,也不能在声明对象后利用赋值运算对成员变量进行初始化。 成员变量的初始化一般是利用一个名为构造函数的成员函数来完成。,3.1 构造函数,如何进行成员 变量的初始化?,?,构造函数是一种特殊的成员函数,它是在创建对象时(声明或new动态创建)系统自动调用的成员函数。 构造函数的名字必须与类名同名 它不具有任何类型,不返回任何值。,什么是构造函数:,#include class Time private: int hour; int minute; int second; public: Time
2、( )hour=0;minute=0;sec=0;/ 构造函数 void set_time( ); void show_time( ); ;,例 为类Time添加构造函数。,定义成员函数,void Time:set_time() cinhour; Cinminute; Cinsec; void Time:show_time() couthour“:”minute“:”secendl; ,int main() Time t1; /建立对象t1,同时调用构造函数t1.Time() t1.set_time(); /对t1的数据成员赋值 t1.show_time(); /显示t1的数据成员的值 tim
3、e t2(); t2.show_time(); return 0; , 如果用户自己没有定义构造函数,则C+ 系统会自动生成一个构造函数,只是这个构造函数的函数体是空的,也没有参数,不执行初始化操作。 构造函数不需用户调用,也不能被用户调用。,带参数的构造函数,构造函数可以带参数,在调用不同对象的构造函数时,从外面将不同的数据传递给构造函数,以实现不同的初始化。 构造函数首部一般格式为:构造函数名(类型1 形参1,类型2 形参2.); 实参在定义对象时给出,定义对象的一般格式为: 类名 对象名(实参1,实参2,.);,例3.2 有两个长方体,其长宽高为别为:(1)12,20,25;(2)10,
4、14,20.分别求出它们的体积,#include using namespace std; class Box public: Box(int,int,int); int volume(); private: int height; int width; int length; ;,Box:Box(int h,int w,int len) height=h; width=w; length=len; int Box:volume() return(height*width*length); int main() Box box1(12,25,30); cout“The volume of bo
5、x1 is “box1.volume()endl; Box box2(15,30,21); cout“The volume of box2 is “box2.volume()endl; return 0; ,用带初始化表对数据成员初始化,在函数首部对数据成员进行初始化: Box:Box(int h,int w,int len):height(h),width(w),length(len) 表示:用形参h的值初始化数据成员height,用形参w的值初始化数据成员width,用形参len的值初始化数据成员length。,构造函数的重载,在一个类中可以定义多个构造函数,以便对类对象提供不同的初始化的
6、方法,供用户选用。这些构造函数具有相同的名字,而参数的个数或参数类型不同,例 3.3 定义两个构造函数,一个无参数,一个有参数,#include using namespace std; class Box public: Box(); Box(int h,int w ,int len):height(h),width(w),length(len) int volume(); private: int height; int width; int length; ; Box:Box() height=10; width=10; length=10; ,int Box:volume() retu
7、rn(height*width*length); int main() Box box1; cout“The volume of box1 is “box1.volume()endl; Box box2(15,30,25); cout“The volume of box2 is “box2.volume()endl; return 0; ,说明:,调用构造函数不必给出实参的构造函数,称为默认的构造函数。一个类只能有一个默认的构造函数。 建立对象时如果选用的是无参的构造函数,正确的格式是:Box box1;而不是:Box box1(); 一个类中可以包含多个构造函数,对每一个对象来说,建立对象时
8、只执行其中一个构造函数,使用默认参数的构造函数,构造函数中参数的值既可以通过实参传递,也可以指定为某些默认的值。如果用户不指定实参值,编译系统就使形参取默认值。,#include using namespace std; class Box public: Box(int=10,int=10,int=10); int volume(); private: int height; int width; int length; ; Box:Box(int h,int w,int len):height(h),width(w),length(len) int Box:volume() return(
9、height*width*length); ,int main() Box box1; cout“The volume of box1 is “box1.volume()endl; Box box2(15); cout“The volume of box2 is “box2.volume()endl; Box box3(15,30); cout“The volume of box3 is “box3.volume()endl; Box box4(15,30,20); cout“The volume of box4 is “box4.volume()endl; return 0; ,说明:,在声
10、明构造函数时指定默认值,而不是在定义构造函数时指定默认值 声明构造函数时,形参名可以省略:Box(int=10,int=10,int=10); 如果构造函数的全部参数指定了默认值,则在定义对象的时候可以给出一个或者几个实参,也可以不给出实参。 在一个类中定义了全部是默认参数的构造函数后,不能再定义重载构造函数。,析构函数,当一个对象生命周期结束时,其所占有的内存空间就要被回收,这个工作就由析构函数来完成。 析构函数是“反向”的构造函数,析构函数不允许有返回值,更重要的是析构函数不允许带参数,并且一个类中只能有一个析构函数。 被自动调用的情况有两种: 在一个函数体内定义的一个对象,当函数结束时
11、用new运算符动态创建的一个对象,在使用delete释放时,析构函数的特点:,析构函数的作用不是删除对象,而是在撤销对象占用的内存前完成一些清理工作,使这部分内存可以分配给新对象使用。 析构函数不能重载。一个类可以有多个构造函数,只能有一个析构函数。,#include #include using namespace std; class Student public: Student(int n,string nam,char s); Student() cout“Destructor called.“endl; void display() cout“num:“numendl; cout“
12、name:“nameendl; cout“sex:“sexendlendl; private: int num; string name; char sex; ;,Student:Student(int n,string nam,char s) num=n; name=nam; sex=s; cout“Constructor called.“endl; ,int main() Student stud1(10010,“Wang_li“,f); stud1.display(); Student stud2(10011,“Zhang_fun“,m); stud2.display(); return
13、 0; 程序的运行结果应该是什么?,调用构造函数和析构函数的顺序,一般情况下: 先构造的后析构,后构造的先析构。,注意:,在全局范围中定义的对象, 构造函数的调用在最前 局部自动对象,在建立对象时调用其构造函数。在函数调用结束、对象释放时先调用析构函数。 静态(static)局部对象,在程序第一次调用此函数建立对象时调用构造函数。在main函数结束或调用exit函数结束程序时,才调用析构函数。,数组,如果一批数据具有相同的属性,可以把这批数据看作一个有机整体,称为数组。用一个统一的名字代表这批数据,而用序号或下标来区分各个数据。 简言之:数组是有序数据的集合。要寻找一个数组中的某一个元素必须给
14、出数组名和下标。,3.4 对象数组,定义对象数组格式为: 如: Student stud50; /共50个Student对象空间,对象数组的初始化,Student Student(int); /构造函数只有一个参数 Student stud3=60,70,78; Student stud3=60,70,78,45;,Box Box(int,int,int) Box box13=12,25,30; Box Box(int=1,int=1,int=1) Box box13=12,25,30;,建议,Box a3= Box(10,12,15), Box(15,18,20), Box(16,20,26
15、) ,使用对象数组的方法,#include using namespace std; class Box public: Box(int h=10,int w=12,int len=15):height(h),width(w),length(len) int volume(); private: int height; int width; int length; ; int Box:volume() return(height*width*length); ,int main() Box a3= Box(10,12,15), Box(15,18,20), Box(16,20,26) ; co
16、ut“volume of a0 is “a0.volume()endl; cout“volume of a0 is “a1.volume()endl; cout“volume of a0 is “a2.volume()endl; return 0; ,3.5 对象指针,指向对象的指针 建立对象时,编译系统为每个对象分配一定的存储空间,以存放其成员。对象空间的起始地址就是对象的指针。因此可以定义一个指针变量,用来存放对象的指针。,Class Time public: int hour; int minute; int sec; void get_time( ) couthour“:”minute
17、; cout“:”secend; ;,Time *pt; Time t1; pt=,对象有地址,存放对象初始地址的指针变量是指向对象的指针变量。对象中的成员也有地址,存放对象成员地址的指针变量就是指向对象成员的指针变量。 定义指向数据成员的指针变量的一般形式为:,指向对象成员的指针,数据类型名 * 指针变量名; 如:int * p1; p1=&t1.hour;,指向对象成员函数的指针,指向普通函数的指针变量的定义方法: 数据类型名 (*指针变量名)(参数表列) 如:void (*p)( ); 给指针变量赋值:p=fun; 用指针调用函数: (*p)( ),定义指向公有成员函数的指针变量的 一般
18、形式: 数据类型名(类名:指针变量名)( ); 如:void(Time:*p2)( ); p2=,成员函数与普通函数的一个根本区别是:它是类中的一个成员,不能在类外 直接用用成员函数名作为函数入口去调用成员函数,因此要求指向成员函数的指 针进行赋值的时候必须在以下三个方面匹配: (1)函数参数的类型和参数个数 (2)函数返回值类型 (3)所属的类,class Time public: Time(int,int,int); int hour; int minute; int sec; void get_time( ); TimeTime(int h,int m,int s) hour=h; mi
19、nute=m; sec=s; void Timeget_time( ) couthour: minute: secendl;,int main( ) Time t1(10,13,56); int *p1= ,This 指针,问题,每个对象中的数据成员分别占用存储空间,如果同一个类定义了多个对象,则有n组同样大小的空间存放n个对象中的数据成员。但不同对象都调用同一个函数代码段。那么,当不同对象的成员函数引用数据成员时,怎么能保证引用的是所指定的对象的数据成员呢?,在每一个成员函数中都包含一个特殊的指针,这个指针的名字是固定的,称为this。它是指向本类对象的指针,它的值是当前被调用的成员函数所在
20、的对象的起始地址。,this指针是隐式使用的,它作为参数被传递给成员函数,如在程序中成员函数volume定义如下: int Box:volume( ) return(height*width*length); C+把它处理为: int Box:volume(Box *this) return(this-height*this-width*this-length); 在调用成员函数a.volume时,实际上是用以下的方式调用的: a.volume( 将a的地址传递给this指针。然后按this的指向去引用各成员。,共用数据的保护,数据能在一定范围内共享,又要保证它不被任意修改,这时可以使用con
21、st,即把有关的数据定义为常量。, 一般常量,指简单类型的常量。如: const int m=15; m=20; int const x=2; /一般常量定义时,两种方式一致。 int const a5=1,2,3,4,5; /元素为常量,不能修改,常对象, 在定义对象时指定对象为常对象。常对象必须要有初值 Time const t1(12,34,46); /t1是常对象 如: class A public: A(int i,int j):x(i),y(j) private: int x,y; ; const A a1(3,4); A const a2(8,9);,一个对象被声明为常对象,则不
22、能调用该对象的非const型的成员函数 有时在编程时有要求,一定要修改常对象中的某个数据成员的值对该数据成员声明为mutable,常数据成员,如: const int hour; Time:Time(int h) hour=h; Time:Time(int h):hour(h),在一个类中,有些数据成员的值允许改变,另一些数据成员的值不允许改变,则可以将一部分数据成员声明为const,以保证其值不被改变。,注 意,不能采用在构造函数中对常数据成员赋初值的方法,只能通过构造函数的参数初始化表对常数据成员进行初始化.,常成员函数,常成员函数,则只能引用本类中的数据成员,而不能修改它们。例如:输出数
23、据成员,返回私有成员值等。,如 : void get_time( ) const;,常成员函数不能调用另一个非const成员函数。 常成员函数可以引用const数据成员,也可以引用非const的数据成员。 const数据成员可以被const成员函数引用,也可以被非const的成员函数引用。,小结,指向对象的常指针,将指针变量声明为const型,这样指针值始终保持为其初值,不能改变。,Time t1(10,12,15),t2; Time * const ptr =,定义指向对象的常指针的一般形式为: 类名 * const 指针变量名=对象地址; 且应该在定义指针变量时就使之初始化。 Time *
24、const ptr1; ptr1=&t1;,注意: 指向对象的常指针变量的值不能改变,即始终指向同一个对象,但可以改变其所指向对象中数据成员的值。 当想将一个指针变量固定的与某一个对象相联系(即该指针变量始终指向一个对象),可以将它指定为const型指针变量。这样可以防止误操作,增加安全性。 常用常指针作为函数的形参,目的是不允许在函数执行过程中改变指针变量的值,使其始终指向原来的对象。,指向常对象的指针变量,定义指向常变量的指针变量的一般形式为: const 类型名 *指针变量名 const char *p1; const char c =“boy”; p1=c; 说明: (1)如果一个变量
25、已被声明为常变量,则只能用常指针指向它,而不能用一般的指针变量指向它。 (2)指向常变量的指针可以指向长变量,也可以指向未被申明为const的变量 (3)如果函数的形参是指向非const型变量的指针,实参只能是指向非const变量的指针;如果形参是指向const型变量的指针,实参可以是指向const变量的指针或非指向const变量的指针。,定义指向常对象的指针变量的一般形式: Const 类名 *指针变量名 Time t1(10,12,15); Const Time *p=&t1; 说明: (1)如果一个对象已被声明常对象,只能用指向常对象的指针指向它,不能用一般的指针变量去指向它 (2)如果
26、定义了一个指向常对象的指针变量,则使它指向一个非const的对象,则其指向的对象不能通过指针来改变。 (3)指向常对象的指针最常用于函数的形参,目的是保护形参指针所指向的对象,使它在函数执行过程中不被修改。 (4)定义了一个指向常对象的指针变量,不能通过它改变指向对象的值,但是指针变量本身的值可以改变,定义指向常对象的指针变量的一般形式为: const 类型名 *指针变量名;,定义指向对象的常指针的一般形式为: 类名 * const 指针变量名;,区分,Time * const p /指向对象的常指针 const Time *p /指向常对象的指针,int main() void fun(co
27、nst Time *p); Time t1(10,13,56); fun( ,一条规则: 当希望在调用函数时对象的值不被修改,应当把形参定义为指向常对象的指针变量,同时用对象的地址作实参(对象可以是const或非const型)。如果要求改对象不仅在调用函数过程中不被改变,而且要求它在程序执行过程中都不改变,则应将它定义为const型(即常对象)。,能否不用指针直接用对象名作为形参和实参,达到同样的目的呢?,int main() void fun(Time t) Time t1(10,13,56); fun(t1); coutt1.hourendl; return 0; void fun(Tim
28、e t) t.hour=18;,在函数中可以修改形参t的值,但不能改变其对应的实参t1的值。在函数调用过程中,将建立一个新的对象t,t是实参t1的拷贝。实参把值传给形参,二种分别占有不同的存储空间。这种形式的虚实结合,要产生实参的拷贝,当对象的规模较大时,时间和空间开销都比较大,因此常用指针作为函数参数。,对象的常引用,使用const来说明引用。该引用所引用的对象不能被更新。而引用本身是不能重新赋值,来实现对另一个对象的引用。,class Time public: Time(int,int,int); int hour; int minute; int sec; ; Time:Time(int
29、 h,int m,int s) hour=h; minute=m; sec=s; ,例:,void fun(const Time ,如果不希望在函数中修改t1的值,可以把引用变量t声明为const(常引用) 则函数原型为:void fun(const Time &);,Const型数据的小结,对象的动态建立和释放,1、new运算符,用来动态创建对象。如: new Box; /编译系统开辟了一段内存空间,并在此空间中存放一个Box类对象,同时调用该类、/的构造函数,以使该对象初始化。 用new运算符动态的分配内存后,将返回一个指向新对象的指针的值,即所分配的内存空间的起始地址。用户可以获得这个地
30、址,并通过这个地址来访问这个对象。因此需要定义一个指向本类的对象的指针变量来存放这个地址。 Box *pt; Pt=new Box;或 Box *pt=new Box(12,15,18);,2、delete运算符,delete pt;,例:,#include class AA public: AA(int i,int j) A=i;B=j; coutprint( ); a2-print( ); delete a1; delete a2; ,调用构造函数,调用析构函数,Constructor,Constructor,1,2,5,6,Destructor.,Destructor.,3.8 对象的赋
31、值和复制,一、对象的赋值 如果一个类定义了两个或多个对象,则同类对象之间可以互相赋值。或者说,一个对象的值(对象中所有数据成员的值)可以赋给另一个同类的对象。 对象赋值的一般形式是:对象名1=对象名2; 注意:对象名1和对象名2必须属于同一个类。 eg:Student stud1,stud2; stud2=stud1;,#include using namespace std; class Box public: Box(int=10,int=10,int=10); int volume(); private: int height; int width; int length; ; Box:
32、Box(int h,int w,int len) height=h; width=w; length=len; ,int Box:volume() return(height*width*length); int main() Box box1(15,30,25),box2; cout“The volume of box1 is “box1.volume()endl; box2=box1; cout“The volume of box2 is “box2.volume()endl; return 0; ,对象的复制,有时候需要用过多个完全相同的对象。C+里面提供了克隆对象的方便易行的办法: 对
33、象的复制机制: Box box2(box1);/用已有的对象box1去克隆一个新对象box2. 一般形式为:类名 对象2(对象1); 可以看出:给出的参数不是一般的变量,而是对象。 建立一个新的对象时调用一个特殊的构造函数复制构造函数,复制构造函数,实现了在初始化时将一个已知对象的数据成员的值拷贝给正在创建的另一个同类的对象。当然,它具有一般构造函数的所有特性。,格式为: :(&) ,BoxBox(const Box ,例:,复制构造函数也是构造函数,只有一个参数,是本类的对象,采用对象的引用形式(一般约定加const声明),复制构造函数(续),C+还提供另外一种复制形式 Box box2=b
34、ox1; 一般形式为: 类名 对象名1=对象名2; 还可以在一个语句中进行多个对象的复制。 如Box box2=box1,box3=box2;,对象赋值与对象复制的区别:,对象赋值是对一个已经存在的对象赋值,必须要先定义被赋值的对象才能赋值。 对象的复制是从无到有的建立一个新对象,并使它与一个已有的对象完全相同(包括对象的结构和成员的值)。,普通构造函数和赋值构造函数的区别:,(1)形式上: 类名(形参表列);/普通构造函数 类名(类名 & 对象名);/复制构造函数 (2)在建立对象时,实参类型不同。系统根据实参的类型决定调用普通的构造函数或复制构造函数,复制构造函数被自动调用有三种情况:,一
35、、是用一个已知对象初始化一个新对象时 二、是以值调用方式向一个函数传递对象参数时。 三、当对象作为函数返回值时。,void fun(Box b) /形参是类的对象 int main( ) Box box1(12,15,18); fun(box1); /实参是类的对象,调用函数时将复制一个新对象b return 0; ,Box f( ) /函数f的类型为Box类类型 Box box1(12,15,18); return box1; /返回值是Box类的对象 int main( ) Box box2; /定义Box类的对象box2 box2=f( ); /调用f函数,返回Box类的临时对象,并将它
36、赋值给box2 ,静态成员,回顾:如果有n个同类的对象,那么每一个对象都分别有自己的数据成员,不同对象的数据成员各自有值,互不相干。 如果希望有一个或者几个数据成员为所有对象所共有,希望实现数据共享怎么办? 全局变量 静态的数据成员,静态数据成员,静态数据成员是一种特殊的数据成员。它以关键字static开头。它为各对象所共有,而不只属于某个对象的成员。,Class Box public: int volume( ); private: static int height; int width; int length; ;,说明:,如果只声明了类而未定义对象,则类的一般数据成员是不占用空间的,只
37、有定义对象时才为对象的数据成员分配空间。但静态成员不属于某个对象,在为对象分配的空间中不包括静态数据成员所占的空间。静态数据成员实在所有对象之外单独开辟空间。只要在类中定义了静态数据成员,即使不定义对象,也为静态数据成员分配空间,它可以被引用。 静态数据成员不随对象的建立而分配空间,也不随对象的撤销而释放。静态数据成员在程序编译时被分配空间,到程序结束时释放空间。,静态数据成员可以初始化,但只能在类体外进行初始化。 int Boxheight=10; Box(int h,int w,int len):height(h) 将height定义为公有成员,可以有如下访问方式: Box a(15,20
38、); couta.heightendl; coutBoxheightendl;,例:,#include using namespace std; class Box public: Box(int,int); int volume(); static int height; int width; int length; ;,Box:Box(int w,int len) width=w; length=len; int Box:volume() return(height*width*length); int Box:height=10; int main() Box a(15,20),b(20
39、,30); couta.heightendl; coutb.heightendl; coutBox:heightendl; couta.volume()endl; return 0; ,有了静态数据成员,各对象之间的数据有了沟通的渠道,实现数据共享,因此可以不使用全局变量。全局变量破坏了封装的原则,不符合面向对象程序的要求。 公有数据成员与全局变量的区别:静态数据成员的作用域只限于定义该类的作用域。在作用域内,可以通过类名和域运算符:引用数据成员,而不论该类对象是否存在。,静态成员函数,成员函数也可以定义为静态的,如: static int volume(); 静态成员函数是类的一部分,而不是
40、对象的一部分。如果在类外要调用公有的成员函数,要用类名和域运算符: 如:Box:volume(); 当然也允许通过对象名调用静态成员函数,如: a.valume(),静态成员函数的作用不是为了对象之间的沟通,而是为了能处理静态数据成员。,注 意,静态成员函数并不属于某一对象,它与任何对象都无关.无法对一个对象中的非静态成员进行默认访问(即在引用数据成员时不指定对象名)。,static int volume( ); return(height*width*length);,如:,假设volume()是Box的成员函数:,静态成员函数可以直接引用本类的静态数据成员。,调用一个对象的成员函数(非静态
41、成员函数)时,系统会把该对象的起始地址赋给成员函数的this指针。 静态成员函数不属于某一个对象,它与任何对象都无关,因此静态成员函数没有this指针。 静态成员函数与非静态成员函数的根本区别是:非静态成员函数有this指针,而静态成员函数没有this指针。因此静态成员函数不能进行默认访问本类中的非静态数据成员,可以直接引用本类中的静态数据成员。,#include using namespace std; class Student public: Student(int,int,int); void total(); static float average(); private: int
42、num; int age; float score; static float sum; static int count; ;,例,Student:Student(int m,int a,int s) num=m; age=a; score=s; void Student:total() sum+=score; count+; float Student:average() return(sum/count); float Student:sum=0; int Student:count=0;,int main() Student stud3= Student(1001,18,70), St
43、udent(1002,19,79), Student(1005,20,98) ; int n; coutn; for(int i=0;in;i+) studi.total(); cout“The average score of “n“ students is “stud0.average()endl; return 0; ,3.10 友元,在一个类中可以有公用的(public)成员和私有的(private)成员。在类外可以访问公用成员,只有本类中的函数可以访问本类的私有成员。 友元可以访问与其有好友关系的类中的私有成员。友元包括友元函数和友元类.,友元函数,概念:如果在本类以外的其他地方定义
44、了一个函数(可以是不属于任何类的非成员函数,也可以是其他类的成员函数),在类中用friend对该函数进行声明,此函数就为本类的友元函数。 作用:友元函数可以访问这个类中的私有成员。,将普通函数声明为友元函数,#include using namespace std; class Time public: Time(int,int,int); friend void display(Time ,Time:Time(int h,int m,int s) hour=h; minute=m; sec=s; void display(Time ,#include using namespace std;
45、 class Date; /对Data类的提前引用声明 class Time public: Time(int,int,int); void display(const Date,友元成员函数,Time:Time(int h,int m,int s) hour=h; minute=m; sec=s; void Time:display(const Date ,class B; class A int F1(B,/类中使用另一个类对象须先有其说明,/把A中F1说明为友元,/正确: 友元访问私有成员,/错误:A中F2不是友元,一个函数(包括普通函数和成员函数)可以被多个类声明为“朋友”,这样就可以
46、引用多个类中的私有数据,注意,友元类,将一个类(如B类)声明为另一个类(如A类)的“朋友” , B类称为A类的友元类。友元类B中的所有函数都是A类的友元函数,可以访问A类中的所有成员。,声明友元类的一般形式为 friend 类名; class A private: public: friend class B; ;,注 意,(1) 友元的关系是单向的而不是双向的。 (2) 友元的关系不能传递。,#include class A private: int x; public: A(int a)x=a; void print()cout“x=“xendl; friend class B;,clas
47、s B public: void set(int n) A a(5); a.x=n; a.print(); ; void main() A a(5); a.print(); B b; b.set(10);,类模板,类模板,是对一批仅仅成员数据类型不同的类的抽象,只要为这一批类所组成的整个类家族创建一个类模板,给出一套程序代码,就可以用来生成多种具体的类,(这类可以看作是类模板的实例),对两个整数的比较: class compare_int public: Compare(int a,int b) x=a;y=b; int max() return(xy)?x:y; int min() return(xy)?x:y; private: int x,y; ;,对两个浮点数的比较: class compare_float public: Compare(float a,float b) x=a;y=b; float max() return(xy)?x:y; float min() return(xy)?x:y; private: float x,y; ;,定义类模板: template class compare public: copare(numtype a,numtype b
链接地址:https://www.31doc.com/p-2600423.html