




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、.第12章 面向对象程序设计与C+基础程序设计语言是编写程序的工具,程序设计语言的发展反映了程序设计方法的演变过程。随着计算机技术的日新月异,要求软件具有良好的可重用性和可扩展性,这就导致程序设计方法从结构化程序设计方式转变到面向对象程序设计方式。C语言能够很好地支持结构化程序设计,C+不仅兼容C,同时具有面向对象的特征,因此充分支持面向对象程序设计。12.1 面向对象程序设计的基本概念面向对象技术变革了软件设计的传统方法。解决结构化程序设计不足的方法就是限制数据的存取权限,面向对象程序设计把数据和使用此数据的过程封装成一个类(类可看成是一个基本数据类型)。数据的封装和隐藏一方面使得内部数据不
2、被破坏,另一方面程序具有良好的可读性和相对独立性。类的继承机制不仅提高了代码的可重用性,降低了软件开发难度和开发周期,同时程序的修改变得容易,软件结构更加稳定,软件的可维护性大大提高。面向对象软件系统由类的层次结构组成,类的具体实例叫做对象,对象之间通过彼此的联系,共同实现程序的功能。如图12-1所示。数据方法数据方法数据方法数据方法类的层次结构图12-1 面向对象软件系统 面向对象程序设计方法提出一些全新的概念:对象、类、封装、数据隐藏、继承和多态性等。多态性、数据封装和继承共同构筑了面向对象程序设计的三大机制。属性:颜色、进水量、洗涤指示操作方法:进水 排水 洗涤 甩干图12-2 洗衣机类
3、示意图1. 类与对象面向对象的方法学认为,客观世界由对象组成,对象有自己独特的特征和行为,两者密不可分。面向对象的软件技术中,类是将不同类型的数据和与这些数据相关的操作封装在一起的集合体。对象可看成类的具体实例。图12-2描述了洗衣机类。【例12-1】 在现实世界中,钢笔具有笔帽、笔体、笔尖、颜色、形状等属性特征,钢笔具有的行为是书写、灌钢笔水。钢笔作为一个整体,具有独特的属性和行为,它们将被抽象成一个钢笔类。这种自成一体性称为封装性。而你正在使用的钢笔,可以看成钢笔类中的一个具体实例。我们不必关心钢笔的内部结构及实现细节,仅利用钢笔对外提供的操作,即外部接口,就可以方便地使用钢笔。【例12-
4、2】 对于整型类型的数据,可以定义对它的四则运算,这是整型数据具有的行为,四则运算与整型数据封装成一体,命名为“int类”。字符型运算和逻辑运算不可以访问、修改int类中的数据,只有int类中定义的四则运算才能对其进行操作。显然,我们也无需知道四则运算是如何定义的,int类对外界提供的操作接口是“+”、“”、“*”、“/”,可以直接利用这些接口实现整数的四则运算,这叫做数据的隐藏性。2. 数据的封装和隐藏封装强调的是数据和行为的自成一体性,也就是将数据和操作数据的函数代码进行有机的结合,形成“类”。封装具有如下意义:1) 面向对象的程序表现出强烈的可读性和独立性。2) 程序不依赖数据结构的改变
5、,具有良好的可维护性。当数据结构改变时,只有类中对数据进行操作的函数需要修改,程序的其他部分不受影响。3) 对数据起到一定的保护作用。只有类中的函数才可以修改类中的私有数据。 隐藏是指类把对数据的操作信息隐藏在内部,只提供对象对外的操作接口,用户只能看见对象封装接口上的信息,这样可以保护内部数据不被破坏,同时使用者使用起来非常方便,并可以容易地将其扩展成新的产品。3. 类的继承类的继承是指新的派生类可以继承原有父类的全部数据和操作的机制,并可以在派生类中添加新的数据和操作方法。新的派生类又叫子类,原有父类又叫基类或超类。例如,想生产敞篷汽车不用从草图开始,只需要对原有的产品添加新的敞篷功能,这
6、样就会快速开发出一种新的产品。利用类的继承特性,可以非常方便地产生一系列具有相似特征的对象。再看一个类继承的例子。在小学,我们学过数的四则运算,到中学会进一步学到对数、指数等运算,到大学将学到微积分等内容。我们每一次的进步都将继承已学过的知识,在已有的基础上不断扩充新的知识。 4. 消息对象之间通过消息相互联系,也是通过消息让某一个对象完成一定的功能。例如,给洗衣机对象发洗涤的操作信号,洗衣机就会执行洗涤的功能。在面向对象的程序设计中,消息名就是在对象中定义的操作(或称方法),给对象发消息,就是让对象执行某一操作,使对象具有行为的能力。如图12-3所示。边长、顶点求周长 求面积发消息求面积执行
7、操作求面积在C+中的表示:A 求面积(边长,顶点坐标)图12-3 消息机制5. 多态性多态性表示同一种东西有多种形态。例如,与对方通信,这个动作将有多种表现形态,如采用写信的方式、打电话、发电报、发电子邮件等。在面向对象的程序设计中,多态性是指同一个(或相似的)操作作用于不同的对象上可以有不同的独特行为,比如add操作,作用在实数对象上,表现为两个实数相加,作用在虚数对象上,表现为两个虚数相加。面向对象的C+语言允许程序员给不同的对象发同一消息,软件系统会做出决策,即到底执行什么动作。在静态(编译或连接)时就可以分辨的,可通过函数重载实现;在运行时才能分辨的,可通过虚函数实现。利用多态性,用户
8、能够发送一般形式的消息,而将所有的实现细节留给接收消息的对象。这种高层次的抽象, 使得多态性、数据封装和继承共同构筑了面向对象程序设计的三大机制。12.2 面向对象程序设计语言C+简介C语言是一种受到广泛重视和应用的面向过程编程的语言,它采用结构化程序设计技术,即把复杂的模块层层分解为一系列简单模块。人们侧重于开发具有特定功能的函数,而有些数据(特别是全局数据)在函数间可随意传递。结构化程序设计语言无法处理高度复杂的程序,为了弥补结构化C语言的不足,支持面向对象的程序设计的C+语言应运而生。C+语言是一种混合性语言,保留了C语言的全部内容,同时扩展了C语言所不具有的面向对象编程的机制。C+在技
9、术上与C完全兼容,但它具有与C语言完全不同的思维方式,即支持面向对象的程序设计思想,强调对数据进行封装、保护等深入的维护,强调软件的可扩展性、可修改性和可维护性。利用C+语言可以进行结构化编程, 更重要的功能是进行面向对象的编程。12.2.1 C+程序结构本小节主要介绍两个程序, 一个是面向过程的C+程序,见例12-3; 一个是面向对象的C+程序,见例12-4。通过这两个实例,读者可以对C+程序结构有个初步认识。【例12-3】 以下程序实现输入一个整数,求平方根并打印出来。/ 程序名: csqrt.cpp#include /定义cout()、cin()的头文件#include /定义sqrt(
10、)的头文件using namespace std; /使用命名空间stdvoid main() int x; coutx; /从键盘接收数据存入变量x中coutthe squart of number=sqrt(x)endl;/输出数据程序运行情况:input number4the squart of number=2说明:1) C+程序注释行以“/”开头,也可以使用C语言的注释行方式。2) C+程序的后缀通常为cpp。3) cout、cin是C+语言中增加的用来输出和输入的函数,分别代表标准的输出设备对象和输入设备对象。这两个C+函数是在输入输出流头文件iostream内定义的。cout的使
11、用形式:cout变量。4) endl 操作符表示以后的输出换行打印。 5)C标准程序库中的所有标识符都被定义于一个名为std的namespace中,程序中第4行的使用,使得命名空间std内定义的所有C+标准库函数名和标识符都有效,就好像它们被声明为全局变量一样。面向对象程序设计的首要任务是设计类,自顶向下利用演绎的思想,由抽象类派生具体的子类;自底向上利用归纳的思想,由具体的子类归纳出具有共同特征的抽象的父类,从而建立类的层次结构。再以类为模板创建不同的对象,然后协调这些对象共同工作。程序的运行从main函数开始。【例12-4】 编写一个简单的面向对象的C+程序:设计一个sample类, 对整
12、型数据进行管理, 初始化并显示对象。1: #include2: using namespace std; 3:class sample / create a class4: 5: private:6: int i;7: public:8: void initial();9: void display(); 10: ; 11: void sample: initial()/定义类的初始化成员函数12: i = 0; 13 14: void sample: display()/定义类的显示成员函数15: cout i endl; 16 17: void main() 18: sample A;/定
13、义类sample 的对象A19: A.initial();/给对象A 发消息, 进行对象的初始化20: cout Object A ,i = ;21: A.display();/给对象A 发消息, 显示对象22: 运行结果:Object A ,i = 0说明:程序的第310行,用来声明类sample。其中class是C+用来声明类的关键字。该类中定义了私有的整型数据成员i,以及公有成员函数initial()和display()。私有的整型数据成员i只能通过两个公有成员函数进行初始化和显示。 程序的第1113行,用来定义类的公有成员函数initial() ,其作用是初始化对象。程序的第1416行
14、,用来定义类的公有成员函数display() ,其作用是显示对象。程序的第1722行,是主函数,其中第18行用来定义一个具体的对象A,这意味着在内存为对象A分配空间,如图12-4所示。第19行是给对象A发初始化的消息,对象A执行initial()函数,改变对象A的状态,如图12-5所示。第21行是给对象A发显示的消息,对象A执行display()函数,显示对象A的状态。 对象Ai图12-5对象A初始化 0对象Ai图12-4 定义类的对象A12.2.2 C+对C的补充1. 注释行C+的注释有两种类型:一种是沿用C语言的方法,采用“/*”和“*/”括起来进行注释,另一种方法是只能用于C+的单行注释
15、,即从“/”开始,直到所在行的行尾,所有字符都被作为注释处理。2. C+的cin与coutcout、cin是C+语言中增加的用来输出和输入的函数,分别代表输出设备对象和输入设备对象。cout和cin函数的使用方式不随变量的类型变化,这正是面向对象语言所追求的。cout是代表标准输出的流设备,如显示屏。输出操作必须配合操作符“”,表示把该操作符右边的数据输出到显示屏上。cin是代表标准输入的流设备,如输入设备键盘。输入操作必须配合操作符“”,代表从标准输入设备读取数据到内存。 cin与cout 定义在输入输出流头文件iostream.h中。3. 关键字const定义符号常量C+中的符号常量使用关
16、键字const来说明,其一般形式:const 类型说明符 常量名=常量值或类型说明符const 常量名=常量值例如:定义一个buf的常量。const int buf=512或int const buf=5124. new和delete运算符C+新增new和delete作为动态内存分配和释放的操作符,用来增强C语言中原有的函数malloc和free,提高了内存管理的灵活性。例如:int *p; /定义指向整数的指针变量p=new int;/动态申请存放整数的内存空间delete p; /释放p指向的动态内存空间5. 引用作为函数参数C+新增了引用,它使函数调用变得清晰、简单,参数传递效率更高。同
17、时,将引用作为函数参数给编程带来了很大的灵活性。引用可看成某个目标变量的别名,对引用的操作,实际上就是对目标变量的操作,引用与目标变量完全对应。一旦用目标变量给引用赋初值,引用就被维系在该目标变量上,即引用不会再与其他目标变量建立联系。引用不能是空,与此相反,指针变量可以为空。声明并初始化引用的一般格式:数据类型& 引用名=目标变量;其中,“数据类型”是定义目标变量的类型,而“数据类型&”是用来声明引用的。例如:int m;int& kk=m; /声明kk是对整型变量m的引用m=4;kk=10;/此时目标变量m的值通过引用改为10【例12-5】 引用作为函数参数。#include using
18、namespace std;void swap(int&, int&);/声明形参是引用类型void main() int x=10, y=20; coutbefore swap, x=x, y=yendl; swap(x,y);/函数调用,实际传递的是实参地址 coutafter swap, x=x, y=yendl;void swap(int& xx, int& yy)/形参是引用类型 int temp; temp=xx; xx=yy; yy=temp;运行结果:before swap, x=10, y=20after swap, x=20, y=10该程序通过调用函数swap(),交换主
19、函数中变量x和y的值。在主函数中,调用函数swap(x,y)时,实参看起来是值传递,其实传递的是实参地址。在定义函数swap()时,形参是引用类型,这就使得引用xx与目标实参x的地址维系在一起,引用yy与目标实参y的地址维系在一起。在执行函数swap()时,对引用xx与yy的操作,实际上就是对x与y的操作。【例12-6】 指针作为参数实现与上述程序同样的功能。#include using namespace std;void swap( int *, int * );/声明形参是指针类型void main() int x=10, y=20; coutbefore swap, x=x, y=ye
20、ndl; swap(&x, &y);/函数调用,传递实参的地址 coutafter swap, x=x, y=yendl;void swap(int * xx, int * yy)/形参是指针类型 int temp; temp=*xx; *xx=*yy; *yy=temp;运行结果:before swap, x=10, y=20after swap, x=20, y=10该程序在调用函数swap()时,实参是&x与&y, 表明将把x与y的地址传入到形参中, 而形参必须声明为指针类型,接收传进来的地址。在函数swap()的定义体中,*xx是指针变量xx所指向的变量,实际上就是主函数中的变量x;*
21、yy是指针变量yy所指向的变量,实际上就是主函数中的变量y。通过上述两个程序风格的对比,形参是引用时,函数体简练、清晰、可读性好。而形参是指针类型时,函数体内过多的指针运算降低了程序的可读性,容易产生错误。当形参是引用时,传递的是实参本身(通过传递地址的形式),因此当函数被调用时,在函数作用域内, 并没有建立实参的副本,这种机制大大提高了效率,节省了空间。比如,若要传递的参数是结构或类这样较大的数据类型,显然不希望复制副本,以提高参数传递的效率,并节省内存。当形参既不是引用也不是指针变量时,参数传递属于值传递,此时若函数被调用,必须在函数作用域建立实参的副本,这通常以时间和空间的浪费为代价。
22、6. 函数返回类型是引用当函数返回类型不是引用时,实际上是在内存中开辟临时空间存放函数返回的值,而函数返回类型是引用时,不需要这样一个中间过程,即不需要产生临时变量以存放返回值,而直接把返回值传回到主函数中,从而大大提高程序执行的效率,同样也节省了空间。注意 不要返回不在主函数作用域内的变量或对象的引用。【例12-7】 返回引用类型的应用。#include using namespace std;int large;int& max(x,y) large=(xy)?x:y; return large; /返回变量large的引用void main() int d=max(10,46);/返回变
23、量large的引用,使得large的值直接传给d int& f=max(10,56);/引用f与目标large维系在一起7. 内联函数 为了减少函数调用的开销,C+引入了内联函数。 内联函数的功能是强迫C+编译程序直接使用函数体代码替换调用语句,以提高程序的运行速度。内联函数定义的一般形式:inline 函数类型 函数名(形参表) 函数体 如果在类的声明中直接给出成员函数的定义,该成员函数默认为内联函数。通常只将规模较小又使用频繁的函数设计为内联函数。8. 带默认形参值的函数C+允许定义带多个默认形参值的函数。例如,设函数原型声明情况如下:int change(int x=10, int y=
24、20);则函数调用情况如下:change(40); / 形参y采用默认值20change(); / 形参x和y都采用默认值12.2.3 C+中的类1. 类的定义类是由成员组成的,包括一组数据成员和成员函数,其定义的一般形式:class 类名 private: 私有数据和成员函数 public: 公有数据和成员函数 protected: 保护数据和成员函数 ;类的名称由关键字class开始,类的定义体夹在一对花括号中,后面可以跟分号,或一组属于该类的对象。类内的一组成员变量和成员函数可以有以下三种类型:私有数据类型(private)、保护数据类型(protected)、公有数据类型(public
25、)。如果用private来说明类的数据和成员函数,则意味着它们只能被该类中定义的成员函数和友元函数访问。通常数据默认为私有类型,私有类型的保留字private可以省略。如果用protected来说明类的数据和成员函数,则意味着它们只能被该类中的成员函数、友元函数、该类的派生类中的成员函数所访问。如果用public来说明类的数据和成员函数,意味着可以在类的外部(不通过类的成员函数,如主函数)存取数据。类中的公有成员函数提供了该类对外的接口,即通过公有成员函数,才可以访问类的私有数据。2. 类的成员类的数据成员不仅包含普通的数据变量,而且还可以包含其他类的对象。类是一种新的数据类型,而对象可看成是
26、由类定义的变量。类的成员函数对类内的数据成员施加操作,实现类的特定功能。若成员函数很小,可以在类内定义,反之,一般在类外定义。数据成员通常定义为私有或保护类型,以便隐藏和保护数据。成员函数通常定义为公有类型,目的是提供对外的接口,以便能够对类访问。为了在类外定义成员函数,必须指出该成员函数是属于哪个类的,C+中引入了一个符号“:”,称为作用域运算符。在类外定义成员函数的一般形式:函数返回类型 类名:成员函数名(形参表) 函数体 3. 对象的定义类是对具有相同属性和行为的一组相似对象的抽象,而对象是类的具体实例。类可看成是一个抽象的数据类型,而类的对象就是属于类的一个具体变量。类不是一个占有内存
27、的实体,但对象却是。创建类中的对象,就是在内存中创建具体的对象,其含义就是在内存中为类中的数据分配存储空间,它们是对象的具体体现。通常在子函数中、主函数中以及函数的前面采用如下方式定义对象:类名 对象名;这种方式使得对象如普通变量一样,具有一定的作用域(生存期)。 4. 类成员的使用类中的成员,包括数据成员和成员函数。有了对象,若想使用类中的公有成员,可采用以下形式:对象名. 公有数据成员对象名. 公有成员函数例如,m.input(); 是指给对象m发消息input(),对象m执行input()函数。 注意 类中的私有数据只能通过该类的成员函数进行访问,类中的保护数据可被该类的成员函数以及该类
28、的派生类的成员函数或友元函数所访问。5. 类成员的初始化(1) 数据成员初始化类中公有数据成员可像普通变量一样使用,可在定义对象后,在需要时赋初值。假设有一公有数据num,对象名为A,则用如下方式初始化:A.num=10; / 公有数据可以直接使用类中的私有或保护数据只能在类及派生类中的成员函数或友元函数中使用,所以不允许直接引用类的实例对象中的私有或保护数据成员。如例12-6中,类 sample的实例对象为A,由于类sample中的i是私有数据成员,所以不可以采用如下方式赋值:A.i=5; / 错误, 私有数据不可以直接引用对私有数据i的初始化是通过类 sample中的初始化成员函数实现的。
29、(2) 对象的初始化对私有或保护数据成员的初始化可通过对象的初始化实现。对象的初始化就是给对象数据赋初值。对象的初始化一般有两种方式:一是通过类中的普通成员函数,二是通过类中的特殊成员函数。而最通用的是通过类中的特殊成员函数,即构造函数来实现。在12.2.4节例12-10的主函数中,首先定义类DATE的实例对象m,以便给对象数据分配存储单元(参看图12-10),由于构造函数的特殊性,它可以在定义类中的对象的同时,由系统自动调用,初始化对象的数据。普通的初始化成员函数,可用下面的方式初始化类的对象:A.initial(); /参看12.2.1节例12-6此时对象A调用成员函数initial()响
30、应消息,该函数给对象A的私有数据赋初值。12.2.4 C+中的构造函数和析构函数 1. 构造函数在C+中通常自动初始化对象的数据。为了做到这一点,可以定义一个特殊的成员函数,它的名字与类名相同,称为构造函数。构造函数的作用是在对象被创建时使用特定的值构造对象,或者说将对象初始化为一个特定的状态。当我们定义属于类的对象时,系统就自动执行构造函数,初始化具体的对象。如果程序没有声明构造函数,系统会自动地为程序设置一个,此构造函数什么也不做。对象在创建时只是被分配空间,具体的初值只能由用户定义的初始化函数来实现。关于构造函数,给出以下几点说明:1) 构造函数与类名相同。2) 构造函数没有返回类型,也
31、不能是void类型。3) 构造函数不能被随意调用,由系统自动调用。4) 构造函数可以重载,可以带默认形参,可以是内联函数。5) 构造函数可以带参数也可不带参数,不带参数的构造函数称为默认的构造函数。2. 析构函数此外,C+还提供了一种特殊的成员函数,叫做析构函数。当对象被取消时,系统首先会自动调用类的析构函数,然后撤销对象(释放对象所占用的存储空间)。如果程序中没有声明析构函数,则系统会自动为程序设置一个析构函数。如果用new()函数动态分配对象,当动态对象被取消时,系统会调用析构函数。因此,通常在析构函数中设置delete()函数就会自动撤销动态对象。关于析构函数,给出以下几点说明:1) 析
32、构函数的名称与类名相同,但前面加符号“”。2) 析构函数没有返回类型,也不能是void类型,没有参数。3) 析构函数由系统自动调用,不能随意调用,不能重载。4) 一个类中只能有一个析构函数。5) 基类的析构函数可以是虚函数,以便系统调用派生类析构函数,撤销其对象。【例12-8】 编写一个日期类DATE,对年、月、日进行管理,能响应询问日期及判断是否闰年。#include using namespace std;class DATE/定义DATE类int year;/定义类的私有数据, private可省略 int month;int day;public:DATE()/定义类的构造成员函数,
33、初始化对象 year=month=day=0;int leapyear()/定义判断闰年的成员函数 if(year%4=0 & year %100 !=0) | year%400=0) return 1; else return 0; void input()/定义输入数据的成员函数,并对输入的数据进行分析判断 int days=31,28,31,30,31,30,30,31,30,31,30,31; int cc; while(1) cout year month day; if(month = 1 & month 0 & day =cc) break; void disp()/定义显示数据
34、的成员函数 cout Y= year M= month D= day endl;/类声明结束void main()/定义主函数, 实现类的实例化,并给对象发消息 DATE m;/定义对象m, 系统自动调用构造函数初始化对象 m.input();/给对象m发消息input, 使对象的数据发生变化 if(m.leapyear()/给对象发消息, 判断是否闰年 cout Leap year!; else cout Not leap year!; m.disp();/给对象发消息, 显示日期程序运行情况:yearmonthday对象A图12-6 实例化类中的对象Input Year Month Day
35、: 2006 11 8Not leap year! Y=2006 M=11 D=8说明:当在主函数中定义对象m后,具体的对象就存在了,如图12-6所示。由于C+系统可以在定义对象时自动调用构造函数初始化,所以一开始对象m的数据被初始化为0。【例12-9】 带有参数的构造函数,以及析构函数程序。#include using namespace std;class Example int i;public: Example( int x);/带参数的构造函数 Example()i=0;/不带参数的默认的构造函数 void display(); Example() coutDestroyed!end
36、l;/析构函数;Example:Example(int x) i=x; void Example:display() coutI=iendl;void main() Example A(7);/定义对象A, 系统自动调用带参数的构造函数 Example B;/定义对象B, 系统自动调用默认的构造函数 A.display(); B.display();运行结果:I=7I=0Destroyed!Destroyed!12.2.5 C+中的继承继承是C+语言的一种重要机制,该机制实现了对原有类进行扩充,在此基础上进行更具体、更详细的定义。通过继承,新的派生类不仅可以自动获得基类的所有成员变量和成员函数
37、(构造函数和私有函数除外),同时可定义新的成员变量和成员函数,来满足新的软件需求,进一步完善程序设计,提高软件的重用性。1. 派生类在C+中,派生类从一个基类继承的一般形式:class 派生类名:public 基类名 成员变量和成员函数声明; 其中,派生类名是新类名,public是最常用的继承方式,本章主要介绍public继承方式。此外,还有private、protected继承方式,其特殊性可参考其他C+教材。注意 1) 自动从基类继承下来的所有成员变量和成员函数不在派生类的定义中出现,但若需要在派生类中重新定义基类的成员函数,就必须在派生类的声明中列出来,并为其赋予一个新定义,这如同在派生
38、类中新增一个成员函数。2) 任何其他类(包括派生类)的成员函数定义中,不能直接根据名称访问继承下来的基类私有成员变量,但可以使用基类中定义的成员函数间接访问基类的私有成员变量。3) 私有成员函数根本不会被继承。【例12-10】 派生类程序示例(基类是例12-8中定义的DATE类)。/ 定义派生类Holidayclass Holiday: public DATE char name20;/派生类新增加的私有成员变量public: void set_name()/派生类新增成员函数 coutEnter Name of Holiday:; cin.getline(name,80,n);/cin类中输
39、入字符串函数 void input()/更新来自基类的成员函数 coutEnter Date of Holidayendl; DATE:input();/利用作用域调用基类的同名函数 void disp()/更新来自基类的成员函数 DATE:disp(); cout is name endl; ;/ 定义主函数void main()/实现派生类的实例化,并给对象发消息 Holiday H;/定义派生类对象H H.set_name();/给对象H发消息 H.input() ; if(H.leapyear()/leapyear()是继承下来的公有成员函数 cout Leap year!; else
40、 cout Not leap year!; H.disp() ; 程序运行情况:Enter Name of Holiday: May DayEnter Date of HolidayInput Year Month Day: 2000 5 1Leap year!Y=2000 M=5 D=1year, month, daynameset_name()input()disp()leapyear()图12-7 派生类对象实体is May Day说明:派生类对象继承下来基类的私有数据成员变量year, month, day,并添加新的数据成员变量name。派生类继承基类的公有成员函数leapyear(
41、)(其代码可重用,不需要重写),并重新定义基类的公有成员函数disp()和input(),相当于新添加成员函数。另外,添加新的公有成员函数set_name()。如图12-7所示。2. 基类的protected 成员不能在派生类的定义或实现中直接用名称访问基类的私有成员变量。但如果在基类中把成员变量和成员函数标记为protected性质,则在其派生类(以及派生类的派生类)中不仅能继承下来,且可以用名称直接访问,其性质保持为protected。而在其他任何类或函数中,等同于用private来标记。12.2.6 C+中的多态性、函数重载和虚函数多态性是面向对象程序设计的重要特征之一。继承重点研究类与
42、类的层次,多态则研究在不同层次的类中,同名成员函数的关系。所谓多态性就是同样的接口有不同的功能,同样的消息被不同的对象接收时产生不同的行为。C+获得多态性的方式是函数重载、运算符重载和利用虚函数来实现。1. 函数重载普通函数、类的成员函数和友元函数都可以重载。函数重载是指函数名相同,但参数的类型和数量可以不同。系统根据其参数个数、参数类型,调用相应的函数,执行特定的功能。函数重载的意义在于能使用户为某类操作起一个通用的名字,由编译器在编译时来确定选择哪个函数来执行某一操作,从而降低了程序的复杂性。【例12-11】 编写两个函数,分别求整型数和浮点型数的最大值。#include using na
43、mespace std;int max(int a,int b);double max(double a, double b);int max(int a, int b) return (ab? a:b);double max(double a, double b) return (ab? a:b);void main() coutmax(2,5) max(3.5,6.7)endl;运行结果:5 6.72. 虚函数与纯虚函数虚函数可以使程序在运行过程中动态地确定操作所针对的具体对象,从而实现运行时的多态性。声明虚函数的方法是在基类中的成员函数原型前加上virtual。虚函数可以在一个或多个派生
44、类中重复定义,但要求必须与基类中的函数原型完全相同。这时,无论在派生类的相应成员函数前是否加上关键字virtual,都将视其为虚函数。在实际应用中,通常把基类中的虚函数定义为纯虚函数,即只在基类中声明虚函数,而不定义其函数体,将它的具体定义放到各个派生类中。通过该基类指针或引用,就可以在运行时调用所有派生类的虚函数。纯虚函数的声明的语法形式如下:virtual 函数类型 函数名(形参表)=0;【例12-12】 设计一个图形类,利用纯虚函数实现运行时的多态性。要求:计算矩形和三角形的面积。分析:首先定义一个抽象的图形类Shape,在类Shape下可以派生出多种具体的形状。为了求这些图形的面积,只
45、需在类Shape中声明一个纯虚函数getArea(),而将计算具体形状面积的定义放在其派生类中。#include using namespace std;class Shape protected: double x,y; public: void set(double a, double b) x=a; y=b; virtual void getArea()=0;class Triangle:public Shapepublic: void getArea() coutTriangle S=1/2*x*y=0.5*x*yendl;class Rectangle:public Shapepub
46、lic:void getArea() coutRectangle S=x*y= x*y set(3.4,6.7);/给对象t赋值p-getArea();/此时p-getArea()就调用Triangle的函数getArea()p=&r; /p指向Rectangle对象rp-set(3.4,6.7);/给对象r赋值p-getArea();/此时p-getArea()就调用Rectangle的函数getArea()运行结果:Triangle S=1/2*3.4*6.7=11.39Rectangle S=3.4*6.7=22.78小结C语言能够很好地支持结构化程序设计,C+不仅兼容C,同时具有面向对象的特征,因此充分支持面向对象程序设计。结构化程序设计解决问题时,常常把复杂的问题分解为一系列数据和对数据进行处理的过程(或函数),因为数据没有被“隐藏”在对它进行处理的过程中,这导致结构化程序设计存在着巨大的隐患。面向对象技术变革了软件设计的传统方法。面向对象程序设计把数据和使用此数据的过程封装成一个类。数据的封装和隐藏一方面使得内部数据不被破坏,另一方面使程序具有良
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 电工工考试题及答案
- 文化产业管理证书考生心得体会
- 精密医学发展的趋势与挑战试题及答案
- 育婴师文化敏感性的提升考核试题及答案
- 林肯事故测试题及答案
- 卫生管理创新方法与案例试题及答案
- 激光多功能应用试题及答案
- 自主招生网络试题及答案
- 污水管道疏通试题及答案
- 西医临床数据收集技巧试题及答案
- 【农村电商物流最后一公里配送优化探究(论文)7600字】
- 耳穴压豆课件
- 自考15040习新时代思想概论高通过率题库
- Unit 7 Happy Birthday!Section A(教学教学设计)2024-2025学年人教版英语七年级上册
- 中职教育二年级下学期数学《组合数公式》教学课件
- 急性冠脉综合征
- 免疫治疗中假性进展的机制与评估标准
- 保险客户经理劳动合同样本
- 2024养鸡场鸡粪买卖合同范本
- 燃煤发电厂液氨罐区安全管理规定
- 苏教版六年级下册数学期末测试卷【完整版】
评论
0/150
提交评论