要素类和对象模版类的继承.ppt

上传人:本田雅阁 文档编号:2676929 上传时间:2019-05-04 格式:PPT 页数:159 大小:467.51KB
返回 下载 相关 举报
要素类和对象模版类的继承.ppt_第1页
第1页 / 共159页
要素类和对象模版类的继承.ppt_第2页
第2页 / 共159页
要素类和对象模版类的继承.ppt_第3页
第3页 / 共159页
要素类和对象模版类的继承.ppt_第4页
第4页 / 共159页
要素类和对象模版类的继承.ppt_第5页
第5页 / 共159页
点击查看更多>>
资源描述

《要素类和对象模版类的继承.ppt》由会员分享,可在线阅读,更多相关《要素类和对象模版类的继承.ppt(159页珍藏版)》请在三一文库上搜索。

1、C+要素 类和对象 模版 类的继承,预备知识C+、类与对象,C复习,数据类型:在C语言中:基本类型和构造类型 基本类型:整型、浮点型、字符型、双精度型 构造类型:数组、结构、联合、指针、枚举型 数据对象: int n=3; int a3; a0=-1; /整型数据对象 char ch=A;/字符类型数据对象 对象指针: int *p=,C复习,标识符 表达式 语句:赋值句、条件句、循环句、函数调用(输入输出) 函数:返回值类型,函数名,参数列表 递归:直接递归、间接递归,C+介绍,一. C+要素 (Borland C ,VC),*.cpp 注意:C+ 源文件扩展名用 .cpp C 源文件扩展名

2、用 .c,1. 文件扩展名,/* */ 段注释 以 /* 开始 到 */ 结束 / 行注释 到行末,2.注释,例1:const int m=10; /定义m为常量 值 是 10,4. 常量说明 const,例2: const int a =1,3,5,7,9; / 定义a是常量数组,例3. int * const p; /常指针p指向一个固定的地址,例4. const int * q; /指针q 指向常量,可以在任何地方申明一个变量 例 for(int i=0; i5;i+) 其作用域从申明地起到文末或函数末,5. 变量申明,但不能 while(int i) i+;,int f(int a,

3、int b=0); 调用 f(5), 即调用 f(5,0);,6.函数缺省值参数,缺省参数 要写在参数表的右边 int f(int a, int b=0,int c=1);,inline int square(int x) return x*x; 内联函数先编译,效率高,速度快 但只能有四五个语句, 不能有循环语句,条件语句.,7.内联函数,overload abs; int abs(int); float abs(float); 同名不同参数的函数可以重载 系统会自动选择调用,8. 函数重载,定义函数的变量参数 例 int f(int x 为函数 f 的变量参数 调用实参的地址 调用后实参的

4、值可以改变 函数需要两个以上返回值时,用变量参数,9. 引用操作符 &,例 int *p,*q; p = new int (3); q = new int 4; 为p分配一个整形地址(2字节) *p=3 为 q 分配4个整形地址(8个连续字节) delete p; /撤销p的地址 delete q; /撤销q的多个连续地址,10. 动态函数 动态变量 new delete,#include “iostream.h” int a,b; char x,y; coutxy; 从键盘为变量x,y输入数据 cinab; 从键盘为变量a,b输入数据 cout“ x=” xendl; cout yabend

5、l;,11.输入输出,文件输入输出,include “fstream.h” include “stdlib.h”,void main( ) ifstream infile(“datafile1.doc”); if(!infile) cerrn) infilename; outfilen“ ”nameendl; ,一. C+要素 (Borland C 3.1) 1. 文件扩展名 *.cpp 2.注释 /* */ 段注释 / 行注释 到行末 3. 续行 常量说明 const 5. 变量申明 可以在任何地方申明一个变量 6.函数缺省值参数 int f(int a, int b=0);7.内联函数 8

6、. 重载 overload 引用操作符 & 10. 动态函数 动态变量 new Delete 11输入输出,二. 类和对象,1类的定义,class 类名称 private: 数据成员; 成员函数; protected: 数据成员; 成员函数; public: 数据成员; 成员函数; ; /类定义结束 必须有分号“ ;”,class 是保留字, 作用与struct 相同 定义一个结构也叫类。 private(私有), 缺省 protected(保护) , public(公有) 都是访问限制,例 计数器类 存储于文件“count.h”中,class counter private: /私有成员 u

7、nsigned int value; /数据成员 public: /公有成员 counter( ) value=0; /无参构造函数 counter(int x) if(x0)value=x; else value=0;/有参构造函数 void increment( )if(value0)value-; unsigned access_value( )return value; ;,counter c1, c2; /语句1 counter c3(5); /语句2 语句1定义counter 类的对象c1, c2,即实际变量 (实例)。 对象定义时必须为数据成员赋初值即初始化。初始化由类中的构造函

8、数自动完成。语句1 自动调用 counter 类中无参构造函数,使 c1.value=c2.value=0。 语句2定义对象c3, 自动调用有参构造函数使c3.value=5.,2. 对象的定义 object,注意:不能使用c1.value为它赋值; 因为 value 在counter类中是私有成员不可见,只能用成员函数来调用。 对象不能直接调用私有成员,只能通过公有成员函数来调用私有成员 对象调用成员函数,叫发一个消息 为c1发消息: c1.increment( ); /计数器自动加1 c1.decrement( ); / 计数器自动减1,例 计数器测试程序 #include “iostre

9、am.h” #include “count.h” void main( ) counter c1,c2; for( int i=1; i=8;i+) c1.increment( ); cout“ nc1=” c1.access_value( ); c2.increment( ); cout“ c2=” c2.access_value( ); for( i=1; i=5;i+) c2.decrement( ); cout“ nc2=” c2.access_value( ); c1.decrement( ); cout“ c1=” c1.access_value( ); ,测试结果 c1=1 c1

10、=2 c1=3 c1=4 c1=5 c1=6 c1=7 c1=8 c2=8 c2=7 c2=6 c2=5 c2=4 c2=3 c1=3,圆的类,class Circle float radius; public: Circle(float r=0):radius(r)/构造函数 float GetRadius( ); float CircleCircum( ); float CircleArea( ); ;,成员函数类外定义,Circle: Circle(float r) /构造函数 radius = r; float Circle: GetRadius( ) return radius; f

11、loat Circle: CircleCircum( ) return 2*3.14.6*radius; float Circle: CircleArea( ) return 3.1416*radius*radius; ,圆类的测试,#include “iostream.h” #include “circle.h” void main( ) Circle a(3), b(2); cout“Circum of Circle a = ” a.CircleCircum( )endl; cout“Area of Circle b = ” b.CircleArea( )endl; ,长方形类,class

12、 Rectangle float x, y; public: Rectangle(float a=0, float b=0): x(a),y(b) float RecCircum( )return 2*(x+y); float RecArea( )return x*y; ;,a. 对象指针 如同定义一个对象一样,用类名可以申明一个对象指针。 例 counter *p,*q; 申明counter 类的指针,指针没有初始化, 调用指针必须先分配内存,或指向一个变量的地址,否则出严重错误,甚至死机。,3. 对象指针和对象数组,(1) p=new counter(3); 分配一个整形数据内存,这时系统

13、自动调用有参 构造函数初始化*p的value=3; (2)q=new counter3; 分配三个连续整形数据内存,这时系统自动调用无参构造函数初始化 q,q+1, q+2的value都是0。 如果类中没有无参构造函数,语句(2)出错。,确定地址后的对象指针可以调用类中公有数 据及公有函数。 pincrement( ); (q+1) decrement( ); (*p).decrement( ); (*p).decrement( )中的括号不能省略,因为 运算符 . 的优先级高于*; 对象指针用毕,要予以撤销,释放内存, delete p; delete q; 撤销后的指针可以再用,只要重新分

14、配内存或指向一个内存。,b. 对象数组 如果类中有无参构造函数,可以定义对象数组 (3) counter c3; 这时系统自动调用无参构造函数初始化c0,c1,c2的value都是0。 如果类中没有无参构造函数,语句(3)出错。,a. 一个类中的数据成员不可以初始化, 例 class A int value=0;出错 .; b. 另一个类的对象可以做本类的数据成员,但要先定义后作成员。 只先申明不行。本类对象不可以做自己的数据成员。 c. 指向本类或另一类对象的指针,或引用可以作本类的数据成员。 只要先申明就可以。,4. 类的数据成员,d. 公有成员和私有成员的先后次序可以交换。可以把私有成员

15、写在类的前部,也可以写在后部。 e. 本类对象可以调用本类公有数据或公有函数,不能调用私有数据和私有成员。,例 class A; class B A *p; /合法 A /出错 ;,长方形和圆的类,class RecCircle Rectangle Rec; Circle Cir; public: RecCircle(float a, float b, float c): Rec(a,b), Cir(c) float Circum( )return Rec.RecCircum( )+Cir.CircleCircum( ); float Area( ) return Rec.RecArea( )

16、+Cir.CircleArea( ); ;,成员函数也叫类所具有的方法或操作。 函数头叫方法的界面,也叫消息模式。 函数可以重载(要求参数不同)不必用overload。 可以类内申明类外定义,类内定义时不用inline即内联。 成员函数可以调用本类数据成员,无论公有或私有。 对象调用公有成员函数叫做发一个消息。,5. 类的 成员函数,构造函数可以重载,带缺省参数时,要特别注意避免二义性。 构造函数一般都是公有函数。只有私有构造函数的类不能定义对象。 只有本类对象或本类成员函数才能调用成员函数。,成员函数必须由对象调用,调用成员函数的对象可以看作一个隐含的参数,这是一个指针参数,用this表示。

17、this 指针指向调用成员函数的对象。 例 Circle:CircleArea( ) return 3.1416*radius*radius; /其中 radius 实际意义是thisradius . Circle a(3.4); cout a.CircleArea( );/this指针指向a,6. This 指针,this指针,counter:increament( ) if(valuevalue counter c; c.increament( ); /实际参数是c, this 指向c,与类名同名的成员函数叫构造函数,构造函数没有返回类型。构造函数的作用是自动为对象初始化。对象不能调用构造

18、函数。 如果一个类中没有构造函数,系统会自动生成一个无参构造函数。如果一个类中有有参构造函数,系统就不再自动生成无参构造函数,这时,用类定义对象数组或对象指针都可能出错。,7. 构造函数,一个类中如果没有构造函数,系统会自动生成 一个无参构造函数,使所有的数据成员都置0。 一个类中如果有有参构造函数,系统就不再生 成无参构造函数。 例如 RecCirle类中,就没有无参构造函数。 这时要小心,下面一个语句会出错 RecCircle d; /出错 无法初始化 RecCircle s3; /出错 无法初始化 正确的定义形式是 RecCircle d(2.0, 3.5, 4);,8. 拷贝构造函数,

19、构造函数的参数不能是本类对象,但可以是本类对象的引用, 这样的构造函数叫拷贝构造函数。,class Circle, float radius; public: Circle(float r=0):radius(r)/构造函数 Circle(Circle ,1) 用已有对象定义新的对象。 Circle a(2); Circle b(a); 第二个语句就是利用拷贝构造函数定义赋数对象b, b的半径等于a的半径。,拷贝构造函数的作用:,拷贝构造函数的作用:,2) 本类对象作函数的参数时,要用拷贝构造函数传值。 3) 一个函数的返回值是本类对象时,要用拷贝构造函数赋值。 Circle Fun(Circ

20、le t) return Circl(2*t.radius);,如果类中没有拷贝构造函数系统会自动生成一个。 如果类中有指针成员,就必须专门定义拷贝构造函数,否则可能出错。,例 class A int *p; pubic: A( )p= new int(0); A(A,以开头与类名同名的成员函数称为析构函数。析构函数无参无返回值。 例 class A A( ); ;,9. 析构函数,析构函数的作用: 当本类的一个对象用完后,系统自动调用析构函数,撤销内存。 这种情况常在一个函数中发生,一个对象在函数中作局部变元,函数用毕后,局部变元失效,析构函数就会自动起作用。 类中没有析构函数时系统会自动生

21、成一个析构函数。 当类中含有指针对象时,应当定义一个析构函数,以免指针指向的内存挂起失。,class A int *p; public: A( )p=new int; A( )delete p; ; 注意 类外对象指针用 new 分配的内存,不会调用析构函数,而要用delete释放。,例 坐标点point类,class Point public: Point(int,int); /构造函数 Point(Point /重载*,Point operator-( ); /一元函数重载 Point,Point:Point(int a, int b) x=a; y=b;,Point:Point(Poin

22、t,int Point:get_x( ) return x;,int Point:get_y( ) return y;,Point Point:operator+(Point ,Point Point:operator *(int n) x=n*x; y=n*y; return*this;,Point Point:operator-( ) x=-x; y=-y; return *this;,Point,istream ,ostream ,除了少数几个操作符,如 “,” ,“:” ,“?:” ,“ ”之外,其余都可以重载。 二元运算在成员函数看来,只有一个参数,另一个是this指针。 例 Poi

23、nt Point:operator +(Point 二元运算+在复数类中重载,变成只有一个参数。,11. 运算符(操作符)重载,Point a1(1,2) , a2(2,-1); a1=a1+a2; 表达式a1=a1+a2中对象a1调用运算+,实 际参数为a2,返回值还是 Point类型, 还可以再调用运算符+,因此表达式 a1+a2+a1有意义。,在class Point 中重载赋值函数 class Point Point,12. 赋值函数重载,赋值函数的作用是把一个对象的所有内容,赋予另一个对象. c1=c2; c1=c1+c2; 类中没有赋值函数时系统会自动生成一个赋值函数。当类中含有指

24、针对象时,应当定义一个赋值函数,以保证值把内容赋值,而不是把地址赋值造成析构函数调用时出错。,例 class A int *p; public: . A,一元运算作成员函数重载时变成零元函数。 Point Point : operator -( ) x=-x;y=-y;return return *this; 调用写成 -c1 或 c1=-c2;,13. 一元运算重载,10. 友元,友元有权访问类内所有成员,不论公有,保护,还是私有成员。 友元没有this指针,必要时可以用类对象的引用作参数。 友元可以是一个类,这时友元类中所有成员函数都是友元。 友元不传递,不对称,不继承。 友元没有this

25、指针,比成员函数多一个参数。,istream ,ostream ,友元不是类的成员,不用类名域 Point:operator,函数在类内申明类外定义 例 日期类保存于“date.h”中,class date int month, day, year; /私有数据 public: date(int, int, int); /有参构造函数 void next( ); void print( ); today;,inline date:date(int a, int b, int c) month=a; day=b; year=c; void date: print( ) coutmonth“ /”

26、day; cout“ /”yearendl;,void date:next( ) switch month case 1: case3: case 5: case 7: case 8: case 10: if(day31)day+; else month+;day=1;break; case 4: case 6: case 9: case 11: if(day30)day+; else month+;day=1;break; case 12: if(day31)day+; else year+;month=1;day=1;break; case 2:,case 2: if(year%4=0)

27、,例 date 类测试程序 #include “ iostream.h” #include “ date.h” void main( ) date today(2,13,2001);/定义对象 date myBirthday(6,24,1983);/定义对象 today.next( );/对象调用操作 today.print( ); myBirthday.print( ); ,测试结果 2/14/2001 6/24/1983,三、模版( template) 通用数据类,模版函数 通用函数 2. 类模版 通用数据类型,模版函数 通用函数,几个形式上完全相同的函数,只有 参数类型和返回值类型不同,

28、可以 写成通用函数,也叫模版函数。,例. int max(int a, int b) return ab?a:b;,float max(float a, float b) return ab?a:b; char max(char a, char b) return ab?a:b; 可以统一写成一个模版函数,template ,T max(T a, T b) return ab?a:b; 这里 T 是类型参数 可以用任意一个标识符,模版函数的调用,对不同的参数都可以调用函数max int a, b; char x,y; a=3; b=5; x= A; y=b; a=max(a, b); 有意义

29、x=max(x, y); 有意义 参数可以用字符串,甚至复杂的结构变 量,对象,只要事先定义大小关系。,2.类模版 通用数据类型,/array.h 例. 通用数组 抽象数组类型 template class Array T *alist; /指针数据 表示一个数组 int size; /表示数组长度 public: Array(int s=50) /构造函数 Array(const Array /输出操作重载 ;,template class Array T *alist; /指针数据 表示一个数组 int size; /表示数组长度 public: Array(int s=50) /构造函数

30、 Array(const Array /析构函数,Array /输出操作重载 ;,/构造函数,template Array:Array(int sz) size = sz; alist = new Tsize; if (alist = 0) cout “内存不够”; return; ,/ 析构函数 destructor,template Array:Array(void) delete alist; ,/ copy constructor 拷贝构造函数,template Array:Array(const Array ,template /赋值函数重载 Array ,/ 将对象X的元素逐个拷贝

31、到当前对象 / copy array items from X to current object T* destptr = alist; T* srcptr =X.alist; while (n-) *destptr+ = *srcptr+; / 返回当前对象的值 /return reference to the current object return *this; ,/一元运算 重载 下标函数 / overloaded index operator,template T ,/强制类型转换,将当前对象 /变成指向它的首地址的指针,,/ pointer conversion operato

32、r template Array:operator T* ( ) const / return address of private array in the /current object return alist; ,/取当前对象的长,template int Array:ListSize( ) const return size; ,/改变当前对象的长度 / resize operator,template void Array:Resize(int sz) / test new size parameter; terminate if size = 0 if (sz = 0) cout

33、 “长度不能小于等于0”;return; / nothing to do if size hasnt changed if (sz = size) return; / request new memory and verify system response T* newlist = new Tsz; if (newlist = 0) cout“内存不够”;return;,int n = (sz = size) ? sz : size;/n取较小的一个 / copy n array items from old to new memory T* srcptr = alist; / addres

34、s at start of alist T* destptr = newlist; / address at start of newlist while (n-) / copy list *destptr+ = *srcptr+; delete alist; / delete old list / reset alist to point at newlist and update the size alist = newlist; size = sz; ,ostream& operator& a), for(int i=0; ia.size; i+) outa.alisti ; outen

35、dl; ,/通用数组类的测试,#include #include “array.h“ void main(void ) Array a(20);/定义长为0的整数数组 for(int i=0;ib(a), c=a; /用拷贝构造函数, /赋值函数建立新对象 coutabc; ,还可以定义字符数组,记录类型数组,复数类的数组,二维数组,三维数组等等,方法与C语言相同。,#include #include “array.h“ #include “complex.h“ void main(void ) Array a(20); complex s(1,2); for(int i=0;ib(a), c

36、=a; coutabc; ,3 多于一个参数的模版,模版可以有不止一个参数,可以是某 个简单类型参数,也可以是通用参数。,例 template class Node, Node *previous, *next; T *T_data; S *S_data; Public: Node(Node*, Node*,T*,S*); Node( ); ,template Node:Node(Node*p, Node*q, T*t, S* s) previous=p; next=q; T_data=t; S_data=s; template Node:Node( ) delete T_data; dele

37、te S_data;,4类模版可以嵌套,template class List Node *head, *current; public: List( ); void Insert( T*, S*); void Remove(T*, S*); List( ); ,四、类的继承,简单继承 多重继承 多态性和虚函数,简单继承,1.派生类的定义 2.基类成员的引用和访问的规则 3.导出类的构造函数 4. 覆盖 作用域分辨 5.派生类的类型转换 6. 导出类的指针,简单继承 从一个类可以派生出新的类派生类或导出类,也叫子类. 原来的类叫基类也叫父类. 1.派生类的定义形式 class 新类名:publ

38、ic 基类名 /公有继承 ; class 新类名:private 基类名 /私有继承 ; /缺省为私有继承, /基类是struct类时缺省是公有继承,基类中的成员自动成为导出类的成员。 基类限制词:public和private指明基类成员在导出类中的访问限制,例:class roadVehicle int wheels, passengers; public: roadVehicle(int, int); void SetWheels(int num); void SetPassengers(int num); int GetWheels(void); int GetPassengers(vo

39、id); void print( ) cout“nwheels=”wheels “nPassengers=”passengers; ;,class truck : public roadVehicle int cargo; public: truck(int,int,int); void SetCargo(int size); int GetCargo(void); void Show(void); void print( ); ;,Truck类有三个数据成员: wheels,passengers cargo. 有9个成员函数,1。构造函数和析构函数 2。重载的操作符和赋值符 3。友元,不继承

40、的部分,基类中同名的成员被派生类中相应的名字覆盖,2.基类成员的引用和访问的规则,保护成员protected数据在基类中同private 公有基类的保护成员和公有成员是导出类的保护和公有成员 私有基类的保护成员和公有成员是导出类私有成员 基类的私有成员在导出类中不可见只能通过基类的公有成员函数调用,例 void truck:print(void) cout“nwheels=”wheels /出错 “npassengers=”passengers /出错 “ncargo=”cargo;,应改为 void truck:print(void) roadVehicle:print( ); cout “

41、ncargo=”cargo; ,3.导出类的构造函数,派生类不继承构造函数和析构函数 派生类的构造函数必须包含基类构造函数的信息 要为基类构造函数提供初始化参数,class truck 的构造函数: truck:truck(int a,int b,int c) : roadVahicle(a,b),如果 roadVehicle类中 roadVehicle:roadVehicle(int x,int y) wheels=x; passengers=y; 则truck类中 truck:truck(int a, int b, int c) : roadVehicle(a,b) cargo=c; ,注

42、意: 导出类的构造函数中未写明基类构造函数 基类构造函数的参数无法传递, 这时导出类自动调用基类的无参构造函数, 如果基类没有无参构造函数,就会出错。,如果派生类中还有基类的对象成员,class truck : public roadVehicle int cargo; roadVehicle a; public: truck(int,int,int,int,int); truck(int x):roadVehicle(x,x+1),a(x,x) cargo=x; void SetCargo(int size); int GetCargo(void); void Show(void); voi

43、d print( ); ;,例 truck类的构造函数,truck:truck(int a1, int a2, int b1, int b2, int c) : roadVehicle(a1,a2), a(b1,b2) cargo=c; ,基类的构造函数由基类名标出 对象成员的构造函数由对象名标出,构造函数的调用顺序 先基类再导出类 析构函数相反,4. 覆盖 作用域分辨,基类中同名的成员被派生类中相应的名字覆盖 例 class A public: int fun( ) return 1; ,class B : public A public: int fun( )/覆盖A中同名元 return

44、 2; ,A a; B b; int i=a.fun( ); / i=1 int j=b.fun( ); / j=2 i=b.A:fun( ); / i=1 作用域分辨,class B : public A public: int fun( )return 2; int f( )return A:fun( ); ,B b; int i=b.fun( ); /i=2 int j=b.f( ); /i=1,例 truck类中的print函数,void truck:print(void) roadVehicle:print( ); cout “ncargo=”cargo; truck t(4,3,4

45、); t.print( ); 输出: wheels=4 passengers=3 cargo=4,5.派生类的类型转换,class A ; class B : public A ;,B是A的派生类, B是A的超集 可以将类B的对象自动转换 为A类对象,反之不成立.,A a; B b; A *ap=new A; B *bp=new B; a=b; /正确 ap=bp; /正确 b=a; /错误 bp=ap; /错误,用户定义类型转换,类型转换函数重载 X:operator T( ); X是原定义类型,T是转换后类型。 不带参数,没有返回类型。T就是返回类型。 例 String:operator

46、char *(void ) return str; operator char *(void )是String类的成员函数 String类对象可以作char*字符串类型使用。,X:operator T( );,X类对象可以作T类型使用 X s; T a=s; /隐式转换 用于初始化 T fun( T t); a=fun(s); /隐式转换 用于函数参数 X f( X t); a=f(s); /隐式转换 用于函数返回值,隐式类型转换的规则:,用于初始化,函数参数,函数返回值 1.标准转换优先(转换成标准类型)。 2.不允许转换再转换 3.必须唯一确定,不能有二义性。 不能用隐式类型转换时用强制类型转换 a= T(s); /显式转换 强制类型转换,6. 导出类的指针,1 公有基类 指向导出类对象的指针可以隐式转换为指向基类对象的指针 反之不成立 class A ; class B : public A ;,A *ap=new A; B *bp=new B; ap=bp; /正确 bp=ap; /错误 bp=(B*)ap;/正确, /显式转换,2.私有基类不能隐式转换,多重继承,class A; class B; class C :public A

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1