C++类以及对象ppt课件.ppt

上传人:牧羊曲112 文档编号:1375490 上传时间:2022-11-16 格式:PPT 页数:76 大小:582.50KB
返回 下载 相关 举报
C++类以及对象ppt课件.ppt_第1页
第1页 / 共76页
C++类以及对象ppt课件.ppt_第2页
第2页 / 共76页
C++类以及对象ppt课件.ppt_第3页
第3页 / 共76页
C++类以及对象ppt课件.ppt_第4页
第4页 / 共76页
C++类以及对象ppt课件.ppt_第5页
第5页 / 共76页
点击查看更多>>
资源描述

《C++类以及对象ppt课件.ppt》由会员分享,可在线阅读,更多相关《C++类以及对象ppt课件.ppt(76页珍藏版)》请在三一办公上搜索。

1、C+语言是C的扩充扩充 C 语言 C+ 语言扩充的目的:支持面向对象程序设计扩充的功能:类定义消息传递(类似函数调用)继承、虚函数,第二章 类和对象,对象与封装,对象 相对独立的实体具有表示其状态、特征的属性具有表示其行为、功能的操作封装性:只有自身操作可访问对象属性面向对象方法将分析、设计的系统和程序都抽象为对象组成的模型面向对象程序设计运行中程序实例 = 若干对象实例 + 交互控制程序 = 若干对象类(用于描述各种对象)对象类 = 程序模块C+程序 = 主函数(main) + 若干类定义,类,C+的类是把各种不同类型的数据(称为数据成员)和对数据的操作(成员函数)组织在一起而形成的用户自定

2、义的数据类型。C+中,类定义包括类说明和类实现两大部分。说明部分提供了对该类所有数据成员和成员函数的描述,而实现部分提供了所有成员函数的实现代码。,类的定义 *.h,class 类名 数据成员的说明public:方法成员的说明;,说明:类名由用户自己定,一般首字母大写默认是private,只有类中的成员函数才能访问注意:类定义的末尾有一分号注意:不能在类定义中对数据成员进行初始化 class Location int x=25,y; /ERROR ;,class Date int year,month,day;public: Date(int y,int m,int d); void setY

3、ear(int y) ; void setMonth(int m) ; void setDay(int d) ; int getYear( ); int getMonth( ); int getDay( ); ;,/ date.h类的定义,成员函数的定义,1、将成员函数的定义直接写在类中适合于成员函数规模较小的情况(内联函数)2、在类的定义体中只写出成员函数的原型说明,而成员函数的定义之后再写通常将类的定义写在一个头文件(.h文件)中,成员函数的定义写在一个程序文件(.cpp文件)中一般形式:返回类型 类名:成员函数名(参数说明)类体 ,class Date int year,month,da

4、y;public:Date(int y,int m,int d);void setYear(int y) ;void setMonth(int m) ;void setDay(int d) ;int getYear( ); int getMonth( ); int getDay( ) return day; /内联函数 ;,/date.cpp 实现部分#include date.h Date: Date(int y,int m,int d) year=y;month=m;day=d;int Date:getYear( ) return year;,int Date:getMonth( ) re

5、turn month;int Date:getDay( ) return day;,void Date:setYear(int y ) year=y;void Date:setMonth(int m ) month=m;void Date:setDay(int d ) day=d;,/exam.cpp Date类的测试程序#include #include date.hvoid main()Date k(2000,12,1);coutk.getMonth()endl;,对象创建时,为数据成员分配存储空间调用类的构造函数对象生命周期结束时,调用类的析构函数,构造函数,是一种特殊的成员函数,函数名

6、与类名相同当定义该类的对象时,构造函数将被自动调用以实现对该对象的初始化构造函数不能有返回值,因而不能指定包括void在内的任何返回值类型构造函数既可定义带参,也可义不带参一个类可定义多个构造函数,也可以不定义构造函数,没定义构造函数时,则自动建立一个空的不带参构造函数(默认构造函数),析构函数,函数名与类名相同,前有没有参数,没有返回值在类对象生命期结束时,系统自动调用一个类只可定义一个析构函数,也可以不定义如果在类的对象中分配有动态内存(如:用new申请分配的内容)时,就必须为该类提供适当的析构函数,完成清理工作,this指针,谁的成员?Date c1,c2; int Date:getYe

7、ar( ) return year; /c1 ? C2? ,this指针,C+的非静态成员函数有一个隐含参数X *const this,int Date:getYear(Date *const this) return this- year; ,c1.getYear(,例:有理数类的定义#include class CRation long n;/ 分子long d;/ 分母public:CRation( long, long ); / 构造void Print( );/ 输出void Gcd( );/ 约分;,CRation:CRation( long n, long d )/ 对象创建时被

8、调用this-n = n;/ this是指向当前对象的指针this-d = d;void CRation:Print( void )cout n / d endl;,void CRation:Gcd( )int x = n, y = d, t;if( x y )t = x; x = y; y = t; t=x%y; while( t != 0 ) x = y; y=t; t = x%y;n /= y; d /= y;,main( ) CRation r( 18, 27 );/ 分配空间,调构造函数 r.Print( ); / 输出 r.Gcd( ); / 约分 r.Print( ); ,例:动

9、态整数数组类,作为对象的数组唯一标识的实体封装数组元素、元素个数等信息责任功能按照下标的访问数组大小可变可获取元素个数,#include #include class Arrayint *pElems; int size; / 个数public:Array( int n ); / 构造Array( void ); / 析构void SetAt( int i, int v );int GetAt( int i ); / 存取int GetSize( void );,类设计要点,独立性表示独立的实体以属性表示其特征以行为表示其担负的责任(功能、服务)封装性不开放属性提供足够的方法,支持各种用途隐蔽

10、内部数据结构隐蔽方法的内部算法复用性适用性强、功能丰富,方法的实现(1/2),Array:Array( int n )/ 构造n元素的数组pElems = new int n ;/ 动态生成size = n; Array:Array( void )/ 撤消前被自动调用delete pElems;/ 释放空间int Array:GetSize( void )return size; / 获得数组大小,方法的实现(2/2),void Array:SetAt( int i, int v )/ 按下标 i 赋值 vif( i = size )/ 超过范围 int *p = new int size +

11、5 ;/ 开辟空间,复制数据 memcpy( p, pElems, size*sizeof(int) ); size+=5; delete pElems;/ 释放原数组空间 pElems = p;/ 保存首地址*(pElems + i ) = v;/ 赋值int Array:GetAt( int i )/ 按下标 i 取元素数据return i size? *(pElems + i): 0;,动态数组的使用,void main( )int n;Array x(10);/ 数组对象实例变量for( int i=0; i n;x.SetAt(i, n);for( i=0; ix.GetSize(

12、); i+ )coutx.GetAt(i) ;,程序分析,对象类 = 数据结构 + 相关函数属性 = 结构分量方法 = 作用于结构的函数对象实例变量静态构造 局部变量、全局变量动态构造 new 类名(参数表)函数定义标识所属的类可以直接访问参数和本类的数据成员函数调用通过对象实例调用其方法,消息传递,对象方法的激活使用者向对象实例发消息对象用方法函数响应消息消息的组成消息名 函数名消息属性 参数值的列表核心点使用者仅关心消息的组成对象决定哪个方法负责响应,消息传递,消息响应不同类可以有同名方法函数同类中可以有原型不同的方法消息响应方法的选择消息名 = 方法名接收消息的对象(对象类)匹配函数原型

13、(参数个数、参数类型),对象成员,一个类的对象作为另一个类的数据成员class X 类名1 成员名1 类名2 成员名2 . ;,构造函数 X:X(参数表0):成员1(参数表1),成员2(参数表2) . ,建立X类对象时,先调对象成员的构造函数,然后才执行X类的构造函数对象成员构造函数的调用顺序取决于这些对象成员在类中的说明顺序析构函数的调用顺序与构造函数相反,#include Date.hclass Student_Info int No; char Name20; char Sex; Date Birthday; public: Student_Info(int n,char *a,char

14、 s,int y,int m,int d); Student_Info( ); int GetNo( ); char * GetName( ); char GetSex( ); ;,#include Student.hStudent_Info:Student_Info(int n,char *a,char s,int y,int m,int d):Birthday(y,m,d) No=n; strcpy(Name,a); Sex=s; Student_Info:Student_Info( ):Birthday(2000,1,1) No=0; strcpy(Name,); Sex=m; ,程序结

15、构,一般分为三个文件:1)将类的说明作为头文件 .h2)将类的成员函数的实现放一个文件 .cpp3) 对类的使用放一个文件,包括main .cpp,作业:定义日期类定义描述书的类,包括书名、价格、出版日期等,第三章 继承,现实世界中的一般特殊关系人 学生人 教师类的继承学生类继承人类教师类继承人类派生类:描述特殊的属性和行为基类:描述一般的属性和行为,C+ 语言对继承的支持,class 派生类 :public 基类/特殊属性/特殊方法;派生类继承了基类的属性和方法支持软件模块的复用复用了基类的数据结构和成员函数,【例】分别定义一个描述圆的类Circle和描述一个圆柱体的类Cylinder。,#

16、ifndef Circle_H#define Circle_Hclass Circle /定义圆类 protected: double radius; public: Circle(double r) radius=r; void setradius(double r) radius=r; double getradius( ) return radius ; double area( ) return 3.14*radius*radius; ;#endif,#include Circle.hclass Cylinder : public Circle /定义圆柱体类 double heigh

17、t; public: Cylinder(double r, double h); void setheight(double h); double getheight(); double area( ); /重新定义area()函数 ;,#include Cylinder.hCylinder:Cylinder(double r, double h): Circle(r) height=h; void Cylinder:setheight(double h) height=h; double Cylinder:getheight( ) return height; double Cylinder

18、:area( ) /重新定义area()函数 return 2*Circle:area( )+2*3.14*radius*height; ,#include #include Cylinder.h#include Circle.hvoid main() Circle s1(10); Cylinder s2(2,5); cout圆柱体表面积:s2.area()endl; cout圆的面积是:s1.area()endl; ,在创建派生类的对象时,由于派生类的对象包含了基类的数据成员,因此派生类的构造函数除初始化其自身定义的数据成员外,还必须对基类中的数据成员进行初始化,也就是说,派生类的构造函数要

19、负责调用基类的构造函数。派生类的构造函数的定义格式如下:派生类名:派生类构造函数名(参数表):基类构造函数名(参数表) ,基类的对象只能调用基类的成员函数,不能调用派生类的成员函数在定义派生类的对象时,系统首先执行基类的构造函数,然后执行派生类的构造函数。而系统执行析构函数的顺序恰恰相反,即先执行派生类的析构函数,再执行基类的析构函数若在基类中没有定义任何构造函数,这时在派生类的构造函数的定义中可以省略对基类构造函数的调用,此时系统将去调用基类的默认构造函数。,多继承,定义多继承类的方式:class 派生类名:访问方式 基类1,访问方式 基类2 ; 其中:访问方式同单继承多继承下派生类的构造函

20、数必须同时负责所有基类构造函数的调用在多继承下,派生类构造函数的定义格式:派生类构造函数名(参数表):基类名1(参数表1), ,在多继承下,系统首先执行各基类的构造函数,然后再执行派生类的构造函数,处于同一层次的各基类构造函数的执行顺序与声明派生类时所指定的各基类顺序一致,而与派生类的构造函数定义中所调用基类构造函数的顺序无关。,第四章 多态性与虚函数,多态性不同事物以不同方式响应同一消息 演出发消息 “暂停” 给 比赛 会议产生不同的消息响应消息响应取决于接受消息的对象,而不是发送者,【例】#include class A int a;public: A(int i=0) a=i; void

21、 print(); ;void A:print () coutIn class A, print() is called.endl; ,class B:public A int b; public: B(int j=-1)b=j; void print(); ;void B:print () coutIn class B, print() is called.endl; ,void main() A a,*pa; B b,*pb; pa= ,void commfun(A /以派生类B的对象b作实参 ,分析:在派生类B中继承了基类A的成员函数print(),又定义了一个同名的print()函数。

22、这种改变在静态联编的基础上编译器并不知道。必须通知编译器这种可能的改变,即需要进行动态联编。其方法就是在基类中将可能发生改变的成员函数声明为虚函数。,虚函数,声明虚函数的方法是在基类中的成员函数原型前加上关键字virtual。其格式如下: class 类名 virtual 类型 函数名(参数表); ;,当一个类的成员函数说明为虚函数后,在该类的派生类中定义与其基类虚函数原型相同的函数。这时,当用基类指针指向这些派生类对象时,系统会在程序运行中根据所指对象的不同,自动选择派生类中的同名函数来代替基类中的虚函数。,虚函数在派生类中重新定义时,必须与基类中的函数原型完全相同,包括函数名、返回类型、参

23、数个数和参数类型的顺序。这时无论在派生类的相应成员函数前是否加上关键字virtual,都将视其为虚函数。如果函数原型不同,只是函数名相同,C+将视其为一般的函数重载,而不是虚函数。,#include class Ppublic:virtual void print() coutParentClassendl;class A: public Ppublic:virtual void print() coutSubClass1endl;class B: public Ppublic:virtual void print() coutSubClass2endl;,void main() A obj1

24、;B obj2; P *s1; s1= ,通过指针,class Apublic:virtual void Print()coutParentendl;class B:public Apublic:virtual void Print() coutSubclassendl;void show(A ,通过引用,void main() B b; show(b); ,纯虚函数,在基类中只声明虚函数而不给出具体的函数定义体,将它的具体定义放在各派生类中,称此虚函数为纯虚函数。通过该基类的指针或引用就可以调用所有派生类的虚函数,基类只是用于继承,仅作为一个接口,具体功能在派生类中实现。形式:virtual

25、 类型 函数名(参数表) =0;,抽象类,若一个类至少有一个纯虚函数,就称该类为抽象类。抽象类中可以有多个纯虚函数,也可以定义其他非纯虚函数。,不能声明抽象类的对象,但可以声明指向抽象类的指针变量和引用变量。如果派生类中没有重新定义基类中的纯虚函数,则在派生类中必须再将该虚函数声明为纯虚函数。从抽象类可以派生出具体或抽象类。引入抽象类的目的,主要是为了能将相关类组织在一个类继承结构中,并通过抽象类来为这些相关类提供统一的操作接口。,【例】 设计一个抽象类shape,它表示具有形状的东西,体现了抽象的概念,在它下面可以派生出多种具体形状,比如三角形、矩形。,#includeclass Shape

26、 protected: double x,y; public: void set(double i, double j) x=i; y=j; virtual void area()=0; /声明纯虚函数 ;,class Triangle: public Shape public: void area() cout 三角形面积: 0.5*x*yendl; ; class Rectangle: public Shape public: void area() cout矩形面积: x*yendl; ;,void showarea(Shape ,接口与复用,程序模块(构件)软件的组成部件软件工程观点:

27、通过组装构件来开发软件对象类作为程序模块,程序模块之间的交互手段:模块接口模块接口 一组函数原型(方法)描述了如何访问该模块编程语言提供接口描述方法C+ 提供抽象类和纯虚函数Java 提供接口 interface,用 C+ 语言描述接口,例:整数容器接口描述用于维护一组整数的程序模块class IntContainer public:virtual int GetNumber( void ) = 0;/ 获得整数个数virtual int GetAt( int idx ) = 0;/ 获得第idx个元素virtual void Add( int val ) = 0;/ 添加元素;纯虚函数:自己

28、不定义,要求派生类必须定义抽象类:仅作为基类,不能直接实例化对象接口 无数据成员、仅提供纯虚函数的抽象类,实现同一功能的两个模块,class IntArray : public IntContainer int*pData, size, used;public:IntArray( int sz ); IntArray( void );int GetNumber( );int GetAt( int idx );void Add( int val );,class IntList : public IntContainerstruct Node int val; struct Node *next

29、; *pHead;public:IntList( );int GetNumber( );int GetAt( int idx );void Add( int val );,两个类的对比,IntArray实现动态数组pData指向数组首元素地址size数组大小used整数的个数IntList实现整数链表Node结点的结构pHead链表首元素地址接口创建方法不同使用方法相同以不同的数据结构、不同的算法提供相同的功能,IntArray 的实现,IntArray:IntArray( int sz ) pData= new int size=sz ; / 申请空间 used =0;IntArray:In

30、tArray( void ) delete pData;/ 释放空间int IntArray:GetNumber( void ) returnused;/ 元素个数int IntArray:GetAt( int idx ) if( idx = used )return-1;/ 超界处理returnpData idx ;,void IntArray:Add( int val ) if( used = size ) / 扩大数组的尺寸(+8)int *p = new int size + 8 ;memcpy( p, pData, sizeof(int)*size );delete pData;/

31、释放原空间pData= p;/ 新的空间size+= 8;pData used+ = val;/ 添加元素,IntList 的实现,IntList:IntList( ) pHead=NULL;int IntList:GetNumber( void ) int n = 0;for( Node *p=pHead; p!=NULL; p=p-next )n+;/ 元素的计数return n;int IntList:GetAt( int idx ) for( Node *p=pHead; p!=NULL; p=p-next )if( idx- = 0 )return p-val;/ 找到指定元素return -1;,int sum( IntContainer *pSet ) int s = 0;for( int i=0; iGetNumber(); i+ )s+= pSet-GetAt(pSet); return s;main( ) IntArray ar(10);IntList ls;ar.Add( 10 ); ar.Add( 23 ); ar.Add( 32 );ls.Add( 10 ); ls.Add( 23 ); ls.Add( 32 );int s1 = sum( ,

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

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号