《面向对象编程技术第四章.ppt》由会员分享,可在线阅读,更多相关《面向对象编程技术第四章.ppt(65页珍藏版)》请在三一办公上搜索。
1、第四章 类与对象,类和对象构造函数与析构函数面向对象的基本特点类的组合前向引用说明类模板/以后介绍面向对象标记要点回顾,认识事物的规律:由简单到复杂!顺序体现第三版本改进了,一、类与对象,类概述,类是具有相同属性和行为的一组对象的抽象集合,为该类的全部对象提供了统一的抽象描述,包括属性和行为两个主要部分。利用类可以实现数据的封装、隐藏、继承与派生。利用类易于编写大型复杂程序,其模块化程度比C中采用函数更高。,慢慢体会,类是一种用户自定义类型,声明形式:class 类名 public:公有成员(外部接口)private:私有成员 protected:保护型成员,2.类的定义:,时钟类的成员(数据
2、成员与函数成员声明),class Clockprivate:int Hour,Minute,Second;public:void SetTime(int NewH,int NewM,int NewS);void ShowTime();,成员函数,数据成员,void Clock:SetTime(int NewH,int NewM,int NewS)Hour=NewH;Minute=NewM;Second=NewS;void Clock:ShowTime()coutHour:Minute:Second;,时钟类的函数成员(定义部分),说明:,关键字public后面声明公有类型成员 它们是类与外部的
3、接口,任何外部函数都可以访问公有类型数据和函数关键字private后面声明私有类型成员 允许本类中的函数访问,类外部的任何函数都不能访问。紧跟在类名称的后面声明私有成员,关键字private可省略(不提倡),说明:,保护类型与private类似,其差别表现在继承与派生时对派生类的影响不同,在第七章介绍。,下页 例子,class circle public:circle:circle(int r)radius=r;int area()return(int)3.14*radius*radius;void circle_prt()coutthe private radius is:radiusend
4、l;private:int radius;,void main()circle circle1(1),circle2(3);coutthe private radius is:circle1.radiusendl;circle1.circle_prt();Circle2.circle_prt();,ERROR!不允许访问私有数据!如何解决?,OK,构造函数,后面介绍,另一例子,说明:,数据成员:,1.与一般的变量声明相同,但需要将它放在类的声明体中。2.不能在定义时初始化赋值定义成员时并不分配存储空间,如 int hour=0,函数成员:,1.成员函数分类(1)构造函数与析构函数(2)其他成员
5、函数2.在类中说明原形,在类外给出函数体实现,并在函数名前使用类名加以限定。也可以直接在类中给出函数体允许声明重载函数和带缺省形参值的函数,建议定义在类外,3.对象的定义,类的对象是该类的实例化,即类类型的变量。声明形式:类名 对象名;例:Clock myClock;,4.类、对象中成员的访问方式,类中成员互访直接使用成员名类外访问使用“对象名.成员名”方式访问 public 属性的成员使用“对象名指针-成员名”方式访问 public 属性的成员,返 回,二、构造函数与析构函数,构造函数名与类名相同构造函数的作用是在对象被创建时使用特定的值构造对象,或者说将对象初始化为一个特定的状态。在对象创
6、建时由系统自动调用。如果程序中未声明,则系统自动产生出一个缺省形式的构造函数,1.构造函数,定义及使用,构造函数举例,class circle public:int radius;int area();circle(int r);int area(int r);,circle:circle(int r)radius=r;int circle:area()return(int)3.14*radius*radius;,void main()circle circle1(5);coutthe circles area is;coutcircle1.area()endl;,定义部分,构造函数与类同名不
7、能指定返回值类型可以是重载函数可以是内联函数如无自定义构造函数,C+系统自动产生空的的构造函数如构造函数带有参数,则在定义对象时必须带上相同类型的实参通过定义类的实例对象,只分配数据成员空间,共享类的代码空间,注意:,析构函数名:类名完成对象被删除前的一些清理工作。在对象的生存期结束的时刻系统自动调用它,然后再释放此对象所属的空间。如果程序中未声明析构函数,编译器将自动产生一个缺省的析构函数。析构函数不带任何参数,2.析构函数,定义及使用,请关注后面的内容!,析构函数举例,class Point public:Point(int xx,int yy);Point();/.其它函数原形 priv
8、ate:int X,int Y;,包含:delete A delete B,注意,命名方式一般类中设计有动态对象,则要设计析构函数析构函数不带任何参数,课堂练习(5分钟):,1.定义一个表述圆的类(数据成员和函数成员),并提供相应的方法2.定义一个表述人的类,(数据成员和函数成员),并提供相应的方法,体会面向对象的编程的特点,3.内联成员函数,为了提高运行时的效率,对于较简单的函数可以声明为内联形式。内联函数体中不要有复杂结构(如循环语句和switch语句)。类中声明内联成员函数的方式:将函数体放在类的声明中。使用inline关键字。,内联函数两种声明方式:显示与隐式,隐式:直接定义在类主体内
9、显示:定义在类主体外,用inline 说明,请看 下页,注意何时采用?,class Point public:void Init(int initX,int initY)X=initX;Y=initY;int GetX()return X;int GetY()return Y;private:int X,Y;,class Point public:void Init(int initX,int initY);int GetX();int GetY();private:int X,Y;inline void Point:Init(int initX,int initY)X=initX;Y=ini
10、tY;inline int Point:GetX()return X;,隐式:显式:,当构造函数的参数为自身类对象的引用时,这个构造函数称为拷贝构造函数.拷贝构造函数的功能是用一个已有对象初始化一个正在建立的同类对象.,4.拷贝构造函数,已存在对象,新对象,克隆,拷贝构造函数在以下三种情况下会被调用:当用类的一个对象去初始化该类的另一个对象时;如果函数的形参是类对象,调用函数进行形参和实参结合时;如果函数的返回值是类对象,函数调用完成返回时。,何时需要它?,定义:,class 类名 public:类名(形参);/构造函数 类名(类名&对象名);/拷贝构造函数.;类名:类名(类名&对象名)/拷贝
11、构造函数的实现 函数体,Point a=a1;/拷贝构造函数 等价于Point a(a1);/可以改成这种形式,Point:Point(Point,class Point public:Point(int xx=0,int yy=0)X=xx;Y=yy;Point(Point,请看 下页,当用类的一个对象去初始化该类的另一个对象时系统自动调用它实现拷贝赋值。void main(void)Point A(1,2);Point B(A);/拷贝构造函数被调用 coutB.GetX()endl;,情形之一,若函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用拷贝构造函数。例如:void f
12、un1(Point p)coutp.GetX()endl;void main()Point A(1,2);fun1(A);/调用拷贝构造函数,情形之二,当函数的返回值是类对象时,系统自动调用拷贝构造函数。例如:Point fun2()Point A(1,2);return A;/调用拷贝构造函数void main()Point B;B=fun2();,情形之三,要看明白书上的例子,返 回,三、面向对象的基本特点,抽象是对具体对象(问题)进行概括,抽出这一类对象的公共性质并加以描述的过程。数据抽象:描述某类对象的属性或状态(对象相互区别的物理量)。代码抽象:描述某类对象的共有的行为特征或具有的功
13、能。,之抽象,?如何实现抽象,通过类的定义。,三、面向对象的设计思想,层层分类,使概念逐渐细化,即具体化。例如,生物分为动物和植物,动物又分为脊椎动物和无脊椎动物,脊椎动物包括哺乳动物,哺乳动物又分为猫、狗,等等,之分类,回 顾,三、面向对象的设计思想,将抽象出的数据成员、代码成员相结合,将它们视为一个整体。增强安全性和简化编程,不必了解具体的实现细节,只需要通过外部接口,以特定的访问权限,来使用类的成员。实现封装:类定义中的,之封装,在设计者允许的权限下,三、面向对象的设计思想,子类与父类子类继承父类所有的属性、方法,并可定义自己的特有属性与方法提高软件开发效率,为软件复用提供强有力的支持多
14、种继承方式:公有、私有、保护;单继承、多继承,之继承,三、面向对象的设计思想,之多态,定义:指类具有相似功能的不同函数使用同一个名称 来实现如:1.运算符重载 2.函数重载 3.虚函数,慢慢领会,插入语,学习复杂、严密的C+语法体系C+既考虑设计理念的先进性,又兼顾程序执行的效率!理解、领会、运用其中的优秀的面向对象程序设计、分析思想!,返 回,是否感觉有点烦!,四、类的组合,类中的成员数据是另一个类的对象可以在已有的抽象的基础上实现更复杂的抽象,注意是对象,例:,class Point private:float x,y;/点的坐标 public:Point(float h,float v)
15、;/构造函数 float GetX(void);/取X坐标 float GetY(void);/取Y坐标 void Draw(void);/在(x,y)处画点;/.函数成员部分,略,class Line private:point p1,p2;/线段的两个端点 public:Line(Point a,Point b);/构造函数 Void Draw(void);/画出线段;/.函数的实现略,1.如何设计组合类的构造函数?,原则:不仅要负责对本类中的基本类型成员数据赋初值,也要对对象成员初始化。声明形式:类名:类名(形参,本类成员形参):内嵌对象1(参数),内嵌对象2(参数),.本类初始化,注意
16、,否则可能是一个不确定的值,2.组合类的构造函数调用,构造函数调用顺序:,若调用缺省构造函数(即无形参的),则内嵌对象的初始化也将调用相应的缺省构造函数。,内嵌对象的构造函数,内嵌对象是客人;声明顺序,调用本类的构造函数,调用本类的析构函数,内嵌对象的析构函数,构造:,析构:,穿衣服与脱衣服,class Point/Point类声明public:Point(int xx=0,int yy=0)X=xx;Y=yy;coutpoint 的构造函数被调用endl;Point(Point,class Line/Line类的声明public:/外部接口Line(Point xp1,Point xp2);
17、Line(Line,Line:Line(Line,例2:,整体类,部件子类1,部件子类2,部件子类n,代码框架,class Whole/整体类public:Whole();Whole(int i,int j,int k);Whole();void Print();private:Part one;Part two;int date;,class Part/部件类public:Part();Part(int i);Part();void Print();private:int val;,下页定义整体类的构造函数,Whole:Whole()date=0;Whole:Whole(int i,int
18、j,int k):two(i),one(j),date(k)./.其它函数的实现略,返 回,五、前向引用声明,类应该先声明,后使用如果需要在某个类的声明之前,引用该类,则应进行前向引用声明。前向引用声明只为程序引入一个标识符,没有具体定义,不能使用该类的具体细节(如对象)。,具体参考教材P112113,前向引用声明举例:,class B;/前向引用声明class A public:void f(B b);class B public:void g(A a);,返 回,template 类声明,六、类模板,使用类模板使用户可以为类声明一种模式,使得类中的某些数据成员、某些成员函数的参数、某些成员
19、函数的返回值,能取任意类型(包括系统预定义的和用户自定义的),目的:,格式:,template 函数模板定义,比较,书上的例子:请先阅读5mins,struct studentint id;float gpa;template class store private:T item;int havevalue;int flag;public:store(void);T getelem(void);void putelem(T x);,templatestore:store():havevalue(1),flag(99)templateT store:getelem(void)if(haveval
20、ue=0)coutno item present!endl;exit(0);elsecoutthe havevalue is:havevalueendl;coutthe flag is:flagendl;return item;,这儿,构造函数定义时,初始化其它数据成员,可以改成class吗?,返 回,templatevoid store:putelem(T x)havevalue+;item=x;void main()student g=1000,23;stores1,s2;s1.putelem(3);s2.putelem(7);couts1.getelem()s2.getelem()end
21、l;,返 回,class circle public:int havevalue;circle(int r);int area()return(int)3.14*radius*radius;void circle_prt()coutthe private radius is:radiusendl;private:int radius;,circle:circle(int r):havevalue(3)radius=r;void main()circle circle1(1);circle*cp;cp=/error,初始化,禁止访问私有数据,返回,返回,返 回,七、面向对象标记,两种方法 UML
22、:统一建模语言 专业的面向对象建模语言,功能强大 较复杂 Coad/Yourdon 类图描述 简单明晰 难以描述成员的访问控制,UML,返 回,要点回顾,1.类与对象的概念,2.基本类的定义与使用,1.类定义的格式:class name,2.访问控制,3.对象创建与撤销,1.类内、类外的理解2.数据成员与函数成员的区别3.public 与private:公共接口与隐藏,1.构造、析构函数:公有、无返回值2.拷贝构造函数,3.组合类,1.定义:类中内嵌对象?问:内嵌类的定义是组合类吗2.组合类构造与析构:调用顺序,4.类模板,1.设计思想:数据处理的通用性,参数化程序设计2.适用范围:普通数据类
23、型、自定义数据类型、类3.注意事项:成员函数是模板函数、代码要通用,返 回,Class Apublic:int a,b,c;private:int x,y,z;,返 回,A a1,a2,a3;,Class Apublic:int a,b,c;private:int x,y,z;,公共接口,内部数据,隐私,返 回,1.构造函数与析构函数的功能?2.默认构造函数:系统可以产生缺省的构造函数与析构函数3.构造函数可以重载,析构函数可以重载吗?,返 回,为什么需要拷贝构造函数?格式:类名(类名&对象名)那些情形调用拷贝构造函数?,1.用同类对象初始化另一个对象2.用于对象参数传递3.函数的返回值是对象
24、,?如何理解,返 回,class outerpublic:int a;class inner public:int b;inner()coutrun the inner constructorendl;void show()coutthe data of inner is:bendl;inn;outer()coutrun the outer constructorendl;void show()coutthe data of outer is:aendl;,void main()outer o1;o1.a=123;o1.inn.b=23;o1.show();o1.inn.show();,返 回
25、,可以这样定义吗?,不提倡,若调用缺省构造函数(即无形参的),则内嵌对象的初始化也将调用相应的缺省构造函数。,内嵌对象的构造函数,声明顺序,调用本类的构造函数,调用本类的析构函数,内嵌对象的析构函数,构造:,析构:,?如何理解,返 回,设计思想皆为参数化程序设计,实现数据处理通用性,1、函数模板:2、类模板:,问题:在函数模板中与类模板中能处理以类为类型参数的通用数据吗?,返 回,template 函数定义(内部使用T),template 类定义,请看下例:,class class_studentpublic:int id;float gpa;class_student(int a,float
26、 b)id=a;gpa=b;class_student();struct struct_student int id;float gpa;,template class store private:T item;int havevalue;int flag;public:store(void);T getelem(void);void putelem(T x);templatevoid store:putelem(T x)havevalue+;item=x;,这样做可以吗?,Storecla_s1;storestr_s1;,回答:,1.请大家一起 看完例子寻找结论2.无论是函数模板还是类模板,其基本目标是一致的,皆为能处理多种类型的数据,只不过一种实现的载体是函数,一种实现的载体是类,实践去探讨,领会!,单元自测(45分钟),见WORD 文档,面向对象的现实渊源,现实中的简化模型,冯.诺依曼计算机,遗传算法,神经网络,谁来开这加飞机?,跳 回,