已阅读5页,还剩43页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C+第15章 C+面向对象基础,15.1面向对象程序设计的基本概念 面向对象技术(Object-Oriented echnology)是在80年代末出现的,它是为了适应开发和维护复杂应用软件的需要,为解决软件危机而诞生的。面向对象的程序设计方法是继结构化程序设计方法之后的一种新的程序方法。在面向对象的程序设计中,通过对象来表示事物,用对象(Object)与对象间消息的传递来表现事物间的联系;用对象的方法实现对对象的操作。什么是对象呢?从概念上讲,对象是代表着正在创建的系统中的一个实体。从实现形式上讲,对象是一个状态和操作(或方法)的封装体。状态由对象的数据结构的内容和值定义,方法是一系列的实现步骤,它由若干操作构成。对对象进行抽象形成类。,抽象是一种提炼对象特征的方法,它可以将具有公共行为的对象组织成类。类是抽象数据类型的实现,一个类的所有对象都有相同的数据结构,并且共享相同的实现操作的代码,而各个对象有着各自不同的状态,即私有的存储。因此,类是所有对象的共同的行为和不同状态的集合体。面向对象技术的基本特征主要有:封装性、继承性、多态性。 封装性:是将数据结构和对数据进行的操作结合在一起,形式一个整体,对外隐蔽其内部实现细节,同时避免了数据紊乱带来的调试与维护的困难。,继承性:是一个对象可以获得另一个对象的特性的机制。对象的特性包括对象的属性(数据)和方法(函数)。继承增强了软件的可扩充性,并为代码重用提供了强有力的手段。 多态性:指相同的函数调用被不同的对象接收时,可以导致不同的行为。它使程序员在设计程序时可以对问题进行更好的抽象,以设计出重用性和维护性俱佳的程序。,15.2类和对象,C+作为C语言的超集,涵盖了C语言的主要概念和功能,但它同时又引入了一些新的概念,其中最主要的是类和对象的概念。类的设计和使用体现了面向对象的设计思想。面向对象的程序设计是从分析对象开始的。对象分析方法的有力工具是分类找出一类具有相同属性的对象,并将它们的共同属性用类表示。在实际的程序设计中,是先定义问题域中的相关对象类(class),然后由类生成对象。因此,类是由用户定义的特殊数据类型。,15.2.1类的定义与实现 类中定义的数据和函数分别称为数据成员和成员函数。类的定义格式一般地分为说明部分和实现部分。说明部分是用来说明该类中的成员,包含数据成员的说明和成员函数的说明。成员函数是用来对数据成员进行操作的,又称为“方法”。实现部分是成员函数的定义。概括起来,说明部分将告诉使用者“干什么”,而实现部分是告诉使用者“怎么干”。类的定义与C语言中的结构体类似,但结构体中只能定义属性不能定义对这些属性进行操作的方法(函数)。,类的定义使用关键字class,其后面的标识符定义了一个新的类型,可以使用这个标识符说明类的变量和指向类的指针。 例:定义一个名为TPerson的类,包括这个人的姓名、年龄、性别、家庭住址、电话等不同属性,以及对这些属性操作的两个函数。 class TPerson /通常用T字母开始的字符串作为类名,以示与 /对象、函数名区别 private: char name20; int age; char sex; char address20; long tel; public: void setdata( ); void print( ); ; /分号不可缺少,面向对象的程序设计强调信息隐藏,将实现细节和不允许外部访问的部分隐藏起来,为此它把类成员分为公开的(public)与私有的(private)两类。外界不能直接访问一个对象的私有部分,它们与对象间的信息传送只能通过公开成员进行。上面的例子中一共定义了7个成员:5个成员数据,2个成员函数。成员数据一般不能让外界直接访问,只能通过本类的成员函数访问。所以把5个成员数据定义成私有成员(用private定义),把成员函数定义为公开成员(用public定义)。,关键字private 、public被称为访问权限修饰符或访问控制修饰符。在一个类的定义中,关键字private 、public出现的顺序与次数可以是任意的。C+规定,类成员隐含的访问权限是私有的,不加声明的成员都默认为私有的。因此,最前面的关键字private可以缺省。而结构体类型的成员的隐含访问权限是公开的。 类的实现,就是进一步定义它的成员函数。成员函数是类定义中用以描述对象行为的成员。在成员函数中,可以直接访问类的所有成员。成员函数的定义方式与普通函数大体相同,以下几点需加以说明:,成员函数可以在类中定义。例如: class TPerson private: char name20; int age; char sex; char address20; long tel; public: void setdata( ) strcpy(name,“liling“); age=18; sex=f; strcpy(address,“249 shanghailu“); tel=3041725; void print( ) coutname“,“age“,“sex“,“address“,“telendl; ;,在类定义外部定义成员函数时,应使用作用域限定符“:”指明该函数是哪个类中的成员函数。例如: class TPerson private: char name20; int age; char sex; char address20; long tel; public: void setdata( ); /函数原型 void print( ); ; void TPerson:setdata( ) /函数实现 strcpy(name,“liling“); age=18; sex=f; strcpy(address,“249 shanghailu“); tel=3041725; void TPerson:print( ) /函数实现 coutname“,“age“,“sex“,“address“,“telendl; ,类的成员函数也可以重载。 例15.1: #include class point int x,y; public: void set(int xp,int yp) /成员函数set x=xp;y=yp; cout“x=“xendl; cout“y=“yendl; ; void set(point p) /成员函数set重载 x=p.x;y=p.y; cout “point:“x; cout“;“yendl; ; void main() point pp,qq; /定义point类的对象pp和qq pp.set(10,20); qq.set(pp); ,运行结果: x=10 y=20 point:10,20 注意:在类定义中,不允许对所定义的数据成员进行初始化。,例15.2分析下面程序的输出结果。 #include class R public: R(int r1,int r2)R1=r1;R2=r2; void print() const; private: int R1,R2; ; void R:print()const coutR1“;“R2endl; void main() const R b(20,52); b.print(); 程序运行结果如下: 20;52,说明: 在类R中,说明了一个常成员函数print()。 常成员函数说明格式如下: () const; 其中,const是加在函数说明后面的类型修饰符,它是函数类型的一个组成部分,因此,在函数实现部分也要带const关键字。 在main()函数中,定义了一个常对象b,只有常成员函数才能操作常对象,没有使用const关键字说明的成员函数不能用来操作常对象。,15.2.2对象的定义 定义了一个类之后,便可以像用int、char等类型符声明简单变量一样,用它们定义对象,也称为类的实例化。有时也可以将对象称为类变量,因为它同变量一样是程序实体,并具有像变量一样的属性,如生存期等存储属性。 类的实例化通过声明语句进行。如已经定义了类TPerson,便可以用声明语句生成对象: TPerson zhang, li;,应当注意,一个类只是定义了一种类型,只有它被实例化,生成对象后,才能接收和存储具体的值。Zhang、li便是两个不同的对象,它们占有不同的内存区域,保存有不同的数据,但它们形式相同,操作代码也相同。对象的定义格式为: 类名 对象名表; 每个对象都是由数据成员和成员函数组成的。既可以访问对象的数据成员,也可以访问对象的成员函数。访问成员函数时,将执行实现该成员函数的代码。C+在实现时,成员函数为该类的所有对象共享。 访问对象的成员使用“.”运算符,其格式为: 对象名.对象成员名,例15.3:使用TPerson类的一个简单程序。 #include #include class TPerson ; void main( ) TPerson my; /声明TPerson类的对象my my.setdata(); /调用TPerson类的成员函数setdata() my.print(); /调用TPerson类的成员函数print() 运行结果如下: liling18f249 shanghailu3041725,用指向对象的指针访问对象的成员,其格式为: 指向对象的指针名-对象成员名 例如: TPerson zhang; /生成TPerson类的对象zhang TPerson *pc; /声明指向TPerson类的对象的指针 pc= 它等价于: (*pc).print();,前面讲述了通过定义成员函数的方法给对象的数据成员赋值。下面讲述如何对对象进行初始化。 在C+中,声明一个类的变量时,可以自动的调用一个用户定义的初始化函数。这个函数是类的特殊的成员函数,称为构造函数。构造函数可以由用户定义,也可以由系统给出。系统给出的的构造函数称为缺省构造函数。缺省构造函数不能对对象中的成员数据进行有效的初始化。当声明一个对象时,程序将自动调用类的构造函数。类的构造函数和类有相同的名字。构造函数不返回任何值,也不能返回void。,例:对类TPerson可以定义如下构造函数取代上面定义的setdata()函数。 TPerson:TPerson(void) strcpy(name,“ liling“); age=18; sex= f ; strcpy(address,“249 shanghailu“); tel=3041725; ,析构函数也是一种特殊的类成员函数,它的功能正好与构造函数相反。析构函数用于释放对象被分配的内存空间,在对象删除前,用它来做一些清理工作。析构函数的名字是类名前加一个“”符号。析构函数不返回任何值,也不能返回void。如果一个类中没有定义析构函数时,编译系统也生成一个缺省析构函数,缺省析构函数是一个空函数。,例15. 43: #include class point int x,y; public: void show(); point() /定义构造函数 x=0;y=0;cout void point:show() coutx“:“yendl; void main() point p; /声明变量时自动调用构造函数。 p.show(); /变量作用域的结尾自动调用析构函数,程序运行结果: Constructor 0:0 Destructor 说明: 1、构造函数和析构函数不能使用return语句返回值。 3、构造函数可以重载,可以有形参;析构函数不能重载。一个类中只可能定义一个析构函数。 何时调用构造函数和析构函数: 1、自动变量的作用域是某个模块,当此模块被激活时,自动变量调用构造函数,当退出此模块时,会调用析构函数。 2、全局变量在进入main()函数之前会调用构造函数,在程序终止时会调用析构函数。 3、动态分配的对象当使用new 时为对象分配内存时会调用构造函数;使用delete删除对象时会调用析构函数。 4、临时变量是为支持计算,由编译器自动产生的。临时变量的生存期的开始和结尾会调用构造函数和析构函数。,15.3派生类与继承,继承性是面向对象程序设计中最重要的机制,也是传统的结构化程序语言所不具有的。它提供了组织程序和复用代码的强有力的手段。 通过继承机制,可以利用已有的数据类型来定义新的数据类型。所定义的新的数据类型不仅拥有新定义的成员,而且还同时拥有旧的成员。例如,要定义一个类TEmployee(职工),它与类TPerson(人)之间有这样的关系:,类TEmployee(职工)是类TPerson(人)的子集。 类TEmployee(职工)的属性要比类TPerson(人)多。一个TPerson类对象增加成员department(部门)和salary(工资)才能得到TEmployee类。 继承可以清晰自然的表达实际问题中分类结构或层次结构,它通过对一个已存在的类进行特殊化来建立新的类。已存在的类称为基类(也称为父类或超类);新建立的类称为派生类(也称为子类)。派生类不但继承了基类所有的数据成员和成员函数,而且可以添加新的数据成员和成员函数,改变所继承的成员函数的语义。,派生类的定义格式如下: class : ; 如:定义TEmployee(职工)类。 class TEmployee: public TPerson char department20; float salary; ; TEmployee(职工)类除了继承TPerson类的所有成员外,又增加了2个新的成员。,例15.5: #include #include class TPerson protected: char name20; int age; char sex; char address20; long tel; public: TPerson(void) strcpy(name,“ liling“); age=18; sex=f; strcpy(address,“249 shanghailu“); tel=3041725; void print( ) coutname“,“age“,“sex“,“address“,“telendl; ;,class TEmployee: protected TPerson /定义新的类TEmployee,它是TPerson类的派生类 protected: char department20; float salary; public: TEmployee():TPerson() strcpy(department,“Computer“); salary=2010.34f; void print() coutname“,“age“,“sex“,“address“,“tel“,“; coutdepartment“,“salaryendl; ; void main() TEmployee te1; /定义TEmployee类的对象te1 te1.print(); /调用TEmployee的成员函数print() 程序运行结果: liling,18,f, 249 shanghailu, 3041725, Computer, 2010.34,常使用如下三种关键字给予表示: public: 表示公有继承。其特点是在公有继承的情况下,在派生类中可以访问基类中的公有成员和保护成员。但不能访问基类的私有成员。 protected: 表示保护继承。其特点是基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然是私有的。,private: 表示私有继承。其特点是基类的公有成员和私有成员在私有派生类中作为私有成员,并且不能被这个派生类的子类所访问,而基类中的私在成员在私有派生类中是不能直接访问的。 将上述三种不同的继承方式的基类特性与派生类特性列出表格,见表15.1 在一般情况下,都使用公有继承,很少使用私有继承。因为私有继承当再派生出下一级时,基类的所有成员都将被私有化,其他类成员也不可再直接访问。如果基类成员只由有血缘关系的成员访问,而不被无血缘关系的对象成员访问时,则要使用保护继承。,private,protected,public作为类成员的可见性修饰符,将产生如下影响: 在一个类中定义的成员函数,可以访问本类中的任何成员,但只能直接访问基类中的protected成员和public成员。 一个类对象,只能直接访问本类或其基类中的public成员。 通过C+语言中的继承机制,可以扩充和完善旧的程序设计以适应新的需求,这样不仅可以节省程序开发的时间和资源,并且为未来程序设计增添了新的资源。,像例15.3.1,从一个基类(TPerson)派生的继承称为单继承。在+语言中,一个派生类可以从一个基类派生,也可以从多个基类派生。从多个基类派生的继承称为多继承。多继承的定义格式如下: class : , , ; 可以看出,多继承的派生类有多个基类。,例15.6定义一个圆柱体类,该类可实现求圆柱体体积,它继承了圆类和高类。圆类可以求圆面积,能描述圆心和半径。类层次结构如图15.1所示。,class Circle float x,y,r; public: Circle(float a,float b,float c)x=a;y=b;r=c; float getx()return x; float gety()return y; float getr()return r; float area()float a; a=r*r*3.14159f; return a; ; class High float high; public: High(float h) high=h; float geth()return high; ;,class Cylinder:public Circle,private High public: float volumn; Cylinder(float a,float b,float c,float d):Circle(a,b,c),High(d) volumn=area()*geth(); float getvolumn()return volumn; ; #include void main() Cylinder a(10,20,15,20); cout“圆柱体的体积为:“a.getvolumn(); 多继承会产生二义性问题。例如: class A public: void f(); ; class B public: void f(); void g(); ;,class C:public A,public B public: void g(); void h(); ; 如果定义一个类的对象c1: C c1; 则对函数f()的访问 c1.f(); 便具有二义性:是访问类中的f(),还是访问类中的f()呢? 解决的方法可以用成员名限定法来消除二义性,例如: c1.A:f(); 或者 c1.B:f(); 也可以在类中定义一个同名成员f(),类中的f()再根据需要来决定调用A:f(),还是B:f(),还是两者皆有,这样,c1.f()将调用C:f()。,下面再讨论另一种情况下的二义性问题。当一个派生类从多个基类派生,而这些基类又有一个共同的基类,则对该基类中说明的成员进行访问时,可能会出现二义性,例如: class A public: int a; class B1:public A private: int b1; class B2:public A private: int b2; class C:public B1,public B2 public: int f(); private: int c; 已知:C c1; 下面的两个访问都有二义性: c1.a; c1.A:a; 而下面的两个访问是正确的: c1.B1:a; c1.B2:a;,C+中通过引入虚基类来解决二义性问题。例如: class A public: int a; class B1: virtual public A /声明为虚基类 private: int b1; class B2: virtual public A /声明为虚基类 private: int b2; class C:public B1,public B2 public: int f(); private: int c; 由于使用了虚基类,使得类A、类B1、类B2、类C之间的关系如图15.4所示,消除了合并之前可能出现的二义性。下面的访问是正确的: C c1; c1.a; c1.A:a;,15.4多态性,当不同的对象接收到相同的消息名(或者说当不同的对象调用相同名称的成员函数)时,可能引起不同的行为(执行不同的代码)。这种现象称为多态性。多态性通过联编实现。联编是指一个计算机程序自身彼此关联的过程。按照联编所进行的阶段不同,可分为两种不同的联编方法:静态联编和动态联编。在C+中,根据联编的时刻不同,存在两种类型多态性:函数重载和虚函数。,静态联编是指联编工作出现在编译连接阶段,在编译时就解决了程序中的操作调用与执行该操作代码间的关系。静态联编所支持的多态性称为编译时多态性。函数重载就属于编译时多态性。 在程序运行时才能确定调用哪一个函数,这种在运行时的函数联编称为动态联编。动态联编所支持的多态性称为运行时多态性。在C+中,只有虚函数才可能是动态联编的。可以通过定义类的虚函数和创建派生类,然后在派生类中重新实现虚函数,实现具有运行时的多态性对象。,虚函数是用关键字virtual修饰的基类中的protected或public成员函数。当成员函数被说明是虚函数时,那么它在所有的派生类及派生类的子类中都是虚函数,即使在派生类中没有明确的使用关键字virtual;然而,这不能颠倒过来:在派生类中说明的虚函数在基类中不能自动成为虚函数。基类和派生类中同一个虚函数不仅要有相同的函数名字,而且函数的参数个数和类型必须相同。否则,派生类中将出现函数的重载(存在两个同名但参数不同的函数)。另外,派生类中的虚函数的返回值类型也必须与基类中的虚函数定义一致。通过使用虚函数实现动态联编使得扩充程序变得容易。,例15.7: class base public:virtual int f(dluble); /定义一个虚函数。虚函数一般和派生类一起使用 ; class derived1:public base public :int f(double); /派生类中的虚函数 int f(int); /函数的参数类型不同,这不是虚函数 ; class derived2:public base public:double f(double); /f()返回值类型与基类中的虚函数定义不同,所以不是虚函数 ;,许多情况下,在基类中不能为虚函数给出一个有意义的定义。这时可以在基类中将它说明为纯虚函数。它的实现留给派生类去做。纯虚函数不能被直接调用,仅起提供一个与派生类相一致的接口作用。声明纯虚函数的形式为: virtual 类型 函数名(参数表列)=0; 包含有纯虚函数的类称为抽象类。一个抽象类只能作为基类派生出新的子类,而不能在程序中被实例化(即不能说明抽象类的对象),但是可以使用指向抽象类的指针。,例15.8计算由几个不同形状的图形组成的总面积。 设要计算的总面积中包括有三角形(triangle)、圆(circle)、矩形(rectangle)的面积。求总面积的一种方法是分别定义不同的类:triangle、circle与rectangle,然后生成各自的一些对象,再一一对它们的面积求和。另一种方法是,
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 私人俱乐部高尔夫球场改造协议
- 人工智能安全使用手册
- 工程力学A卷及(附答案)
- 结婚时新郎父亲的讲话稿5篇
- 2024年度婚姻法律咨询服务协议
- 桥梁建设货车租赁合同协议书范本
- 信息技术招投标投诉处理技巧
- 文化遗产保护国有土地租赁协议
- 临时城市规划师聘用合同模板
- 挖掘土方责任协议
- 【课件】Unit4+Section+B+(Project)课件人教版(2024)七年级英语上册
- 青少年法治教育实践基地建设活动实施方案
- 绿化养护续签合同申请书范文
- 教科(2024秋)版科学三年级上册2.6 我们来做“热气球”教学设计
- 追要工程款居间合同范本2024年
- 2024至2030年中国氮化硅轴承球行业市场全景调查及投资前景分析报告
- 三年级上《时分秒》教材解读
- 公司培训工作报告6篇
- 审计模拟实训教程第四版马春静版部分答案
- 政务服务中心物业服务投标方案(技术方案)
- 鱼苗繁育中的亲鱼选择与培育考核试卷
评论
0/150
提交评论