版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第二帝面向对象程序设计的概念第2章面向对象程序设计的概念VC+应用程序是采用C+语言编写的。C卄是在C语言的基础上进行改进与扩充,是既面向对 象又面向过程的一种混合程序设计语言。传统的程序设计思维方式是基丁“算法+数据结构二程序”的模式,在这类程序中,数据和施加数 据的操作(算法过程)总是分离的,所有程序均有一组被动的数据和一组能动的过程所组成。通常把这 类程序设计称为面向过程的程序设计,把支持这类程序设计的语言称为面向过程的语言 (procedui-e-onented language ,简称POL)。C语言就是其中的一种。C+ +保留了 C语言的基本语法 和流程,C程序儿乎都可以在C+坏境
2、中不作修改被运行。面向对象程序设计(object-oriented programming,简称OOP)将数据及对数据的操作放在一起,作 为一相互依存、不可分割的整体来处理,它采用数据抽象和信息隐藏技术。它将对象及对象的操作抽象 成-种新的数据类型一一类,并IL考虑不同对象之间的联耒和对象类的巫用性。概括为“对象+消息= 面向对象的程序”。本章将在C语言基础上对比介绍C+ +的基本语法,并扩充到面向对象程序设计的基本概念,使读 者能够对在VC+ +应用程序开发中遇到的语法现象有个初步的理解。2.1 C+与C的基本语法区别2.1.1 一般语法区别1.注释c卄支持的注释方法有两种:(1) /*/(
3、2) /"/钉”是C语言中所使用的注释方法,在C+ +中继续延用,一般在连续多行注释时使用。 “”只能单行注释,进行注释的内容从“”后的第一个字符直到本行结束。在使用AppWizard 生成的MFC应用框架中会默认自动插入大量注释如程序清单2所加,“/ TODO"注释行提醒程 序员添加代码的位置和通常所作的操作。程序清单2T:加注释的S+程序BOOL CMainFrame:PieCreateVindoXCREATESTRUCT& cs) if( ?CFrameWnd: PreCreateWindowses) return FALSE;/ TODO: Modify t
4、he Window class or styles here by modifying/ the CREATESTRUCT csretxim TRUE;j注释一行不要太长,一般60个字符以内(保证在VC卄集成编辑环境的可见区域之内),如有超过, 建议换行处理。2. 常量的定义在C语言中,符号常量的定义是通过宏定义#define來实现的,其实质是字符串替换。例如下而语 句定义了一个符号常量PI:#define PI 3.1415926在C卄中保留#debne定义符号常屋的方法,但更多地主张采用关键字const來定义符号常屋。例如 PI的定义可以用下面语句表示:const float PI=3 1
5、415926;注意;用关键字const定义的符号常量必须抬左兵数据类型,而用宏泄义的符号常吊是没仃数据类 型的:用关键字const定义的符号常屋在编译时为其分配相应的内存空间。规定了符号常屋的数据类型, 便于编译系统检查参数的数据类型,C+ +的编译系统检査比C更为严格。3变量的定义在c语言的函数体中,定义部分和执行语句部分是相对分离的,对局部变量的定义必须出现在函数 体或分程序内所冇执行语句之前。C+的函数体不再区分定义部分和执行部分,用户可在函数体的任意 位置定义一个局部变鼠。因此一个变量尤其是中间变量,在需要时再定义,这样便F阅读与维护。例如 可以在for语句中定义循环变量:mt c=l
6、;fdr(mt i=0;i<10 ;i+) c2;在c卄程序中,耍注意区分各种变量的作用范圉和生命周期,变量的类型有:(1) 局部变量(local vanable)在一个函数体内定义的变量,只在本函数范围内有效,在本函数外不能使用。(2) 形参变量(fbnnal parameter)向苗数传送的变虽,同时乂能象其他局部变量一样使用。 全局变屋(global vanable)在函数体外定义的变量,其冇效范围为:从变量定义处开始II到本源文件结束。(4)成员变量(member vanable ):在一个类中定义的变鼠,对类中的所有成员函数都是有效的。在一个继承体系中,根据访问类 型和继承类型
7、的不同,对派生类的作用范围会有不同,参见后面章节对继承的讨论。4. 强制类型转换C卄保留了 C语言的显式强制类型转换法:(类型名)表达式同时还提供了函数表示法:类型名(表达式)例如:mt i=uit(1.35); 给1赋一个初始值函数表示法的函数名只能使用简单类型名称,即int、float, double, char.5动态变量创建C语肓中用函数mallocO动态分配存储空间,用函数dispose。动态释放已分配的存储空间。C卄中提 供了两个类似该函数的运算符new和delete,它们能完成malloc()和dispose()的功能,而II更为方便和 优越。(1) new运算符使用new运算符
8、向内存的“堆”申请某个大小的存储空间,返回存储空间的酋地址。空间大小由 数据类型决定,分配失败返回空指针。使用new的语句格式如下:指针二new数据类型(初始化值)指针二new数据类型算术表达式分配拥有多个连续空间的动态数组例如mt *pi ,*parray;pi=new int(85);分配一个mt型的内存单元,赋初值为85,首地址賦给int型指针pipaiTay=new int10; 分配10个int型(数组)的内存单元,首地址赋给int型指针panay(2) delete运算符delete运算符用来释放通过new运算符得到的内存空间。使用delete的语句格式如下:delete指针del
9、ete 指针 释放整个数组占用的空间例如:delete pi; 释放p指向的内存单元delete parray; 释放parray指向的动态数组内存块,方括号内不要写元索个数6. 输入输出语句在C卄中继续支持使用C的外部库函数(如pnntF和scanf等)进行输入输出,以兼容C程序的执 行。C卄本身引入了流的概念来处理数据的输入输出。所谓的流就是指数据之间的传输操作,包括输入流和输出流。输入流表示数据从我体(如数据文fl > 或设备(如键盘)流向内存的数拯结构,输出流衷示数据从穴存的数据结构流向我体或设备(如显示器)。 流的操作FhC卄的标准库lostream h提供,也就是说,如果要使
10、用流操作必须包含库文件“lostream.h”。输入输出流操作包含两个流对象:输出设备cout和输入设备cm:两个操作符:插入操作符“vv” 和抽取操作符“>>”。进行输出时的语句格式为:cout«输出内容VV输出内容;例如:cout«,a->«a«endl;endl 表示换行,等价 I: "n”进行输入时的语句格式为:cin>>变屋 1»变 B 2.;例女 11: cm»x»y;程序清单2-2演示了两种不同的输入输出方法的使用:程序清单2-2: C与C+的输入输出比较(l)#incl
11、ude <<stdio.hn(2)#include <ciostreainvoid main()void mainO int absum; int a,b、sum;pnntf(4umput a b'J; scanf(t4%d%dn,&a、&b); sum=a+b;prmtfCsum is %dn>siuu);cout«"input a b:”;cui»a»b;sum=a+b;cout«>>sum is >>«siuii«endl;cout和cm的优点是可
12、以口动调整输出和输入格式.而不必象prmtf和scanf都要由使用者一个个指 定;另外cout和cm支持用户自定义的数据类型(pnntf和$canf不支持2.1.2指针和引用引用是C+的一个特征,可以把它看作是一个常虽指针,并自动被编译器逆向引用“指针是指对 象(变量)的地址,而引用是指给对象的地址取一个别名。引用通常应用于函数参数表中作为参数实现 双向传值,但也可以作为一个引用变量使用。1. 引用变量引用变量的说明方式是:类型&引用名=变量名或对象名:例如:int a;mt &b=a;合法定义引用类型mt &c;错!非法定义引用类型b+;这里b是a合法的引用变量,b是
13、a的别名,不再为b分配空间,a,b共用同一存储单元,对b的操 作与对a的操作效果相同,执行b卄等同于执行a*引用变量定义时必须初始化,对此可以这样理解,指针变量的指向可以改变,但作为常量指针的引 用,它的指向是不能改变的,所以在创建一个引用时,它必须指向一个特定的合法的存储空间,并II在 程序运行过程中不能改变。2. 引用参数敲常看到引用的场合是在函数的参数表中。C与C卄函数参数传送是采用单向传值,形参得到实参 的拷贝值。如果需要逆向传值时,即将修改过的参数值反向传递回函数调用处,必须采用传地址的方法, 即使用指针变量,直接操作内存空间。而在C卄中更好的方法是使用引用参数,即把形参定义为引用变
14、 量,编译器会自动地实现逆向传值,引用具有更清晰的语法。程序清单2-3:引用參数举例#niclude "iostream hMvoid AutoInc l(mt*x);void Autolnc2(int &y);void niainOmr a(10);AutoInc 1( &a);cout«Ha=M«a«endl;Autolnc2(a);cout«Ha=M«a«endl; void AutoInc 1 (mt*x)(牧)卄;void Autolnc2(mt &y)g;运行站果:a=lla=12在上面的
15、示例中,定义两个函数AutoInci和Autolnc2的作用都是增1操作。AutoInc 1形参采用的 是指针,调用时需传递地址,而Autolnc2形参采用的是引用。可以看到Autolnc2的实现代码更为简单, 调用时隐藏性好,即调用代码不能确定是传值还是传地址。2.1.3函数的改进1. 函数原型c卄中的函数原型其实就是c语言中的函数声明的概念,用告诉编译系统使用函数的信息,包括 函数的返回类型、参数个数和参数类型。函数原型通常放在程斥的开始部分或者包含在头文件中,确保编译器在该函数被调用以前就已经 “认识”该函数,其语法形式为:返回类型函数名(参数表);例如:char* substiing
16、(chai* str, int stait ,int count);也可写成:char* substnng(char* ,mt, int);C的类型检査的机制较为薄弱,在很多情况下函数声明都可以省略,但在类型检査更为严格的C+ 中,所有函数皆必须川明后才可使用,这便是C卄所特别要求的函数原型。编译系统对下面俏况会给出 错谋信息:(1) 实参和形参的类型不匹配,且实参向形参白动类型转换非法。(2) 实参与形参的个数不一致。(3) 函数没有按函数的类型返回数据。例如:在C+ +中mam函数前必须指明返回类型为void,否则会出现编译错误,main()函数的一般 定义如下:void maiii()函
17、«««5第二帝面向对象程序设计的概念函数直我是指同一个函数名可以对应着务个函数的实现。函数直載允许一个程序内卅明笔个名称相 同的函数,这些函数通常执行相同的功能,但是带有不同类型、不同数目的参数或不同类型的返回值。 例如,要写一个求两个整数之和与两个浮点型数之和的函数如下:mt plus (mt x, int y) return x+y;/幣数求和函数double plus(double x, double y) return x+y; /浮点数求和函数以上实现的是两个不同参数类型的虫取。这样在调用时可用同一个函数名plus调用,程序会口动完 成正确的调用。如:i
18、nt z=plus(2,3); 调用整数求和函数plusdouble z= plus(2.0,3 5); 调用浮点数求和函数plus编译系统解读函数原型,识别重戟。为了使编译系统能确定采用哪一个函数的实现,要求左我函数 的参数个数和参数类型必须有所不同,否则产生二义性错误。3设置默认参数调用函数时.若所用的参数仃个経常用的值.亦卅明函数原型时,可以用该值作为函数参数的默 认值。凡有默认值的参数,在函数调用时如果提供实参,形参则接受实参传递的数值,如果没有给出实 参,形参则接受默认值。例如,下面程序代码中的延时函数,第四次调用delay()时没有给出实参,就 按默认值1000延时,其它调用都给出
19、了实参值,就按给定的数值延时。程序清单24:函数參数獣认值举例#include "lostream h"void delay(int t) if(t=O) return; for(mt i=0;cout«,i=,«K<endl;void mainOvoid delay(int= 1000); 声明默认值参数 delay(0);delay(50);delay (500);delay();delay(5000); 运行结果为:1=501=5001=10001=5000注意:(1)默认参数只能在函数原型中给出,不能在函数定义中给出(2)由实参和形参的匹配
20、顺序是从左到右进行的.当不完全给出默认参数时.默认参数应集中置 于形参序列的右端。下而的语句是错谋的:int fimc(int x=3,int y=5,int z);int func(mt x=3;int 乙int y=5);4.内联函数函数为程序设计的模块化作出了朿耍贡献,但函数的调用也会带来降低程序运行效率的问题,原因 在r调用凶数时,系统必须先保护现场,即保存当前的运行状态和代码地址,而后传递参数给形参,执 行彼调用函数,执行完毕返回时,盂要恢复现场,即要恢复调用函数前的运行状态,根据保存的代码地 址继续执行下一条指令。可见调用函数増加了时间和空间方面的开销,影响了程序运行效率。特别是当
21、 频繁调用一个小函数时,执行函数代码的时间可能很短,而大量的时间花费在调用过程中的保护现场和 恢复现场的工作上。C+ +允许把代码少的小函数设置成内联西数.编译器为内联函数创建代码.亦每次碰到该函数的 调用都用相应的一段代码替换,避免了保护现场和恢复现场的开销,提高了程序的执行速度。从用户的 角度看,调用内联函数和调用一般函数没有任何区别。内联函数有两种定义方法:(1) 在类的外部定义时,把关键字mime加在函数定义之前(2) 把函数原型声明和函数定义合并,放在类定义的内部,则不需要关徒字mime程序清单2-5中所示的程序,在说明函数原型时前面加mime关键字,声明max西数为内联函数。程序清
22、单2-5:内联函数举例声include "iostream.li"void main()int a(8),b(16),c;uiluie mt max(int x,mt y);c=inax(a,b);cout«"c=H«c«endl;uit max(int x,int y)retum(x>y?x:y);内联函数与宏在概念上是不同的,它是真正的函数。编译系统会进行类型检査,执行时会进行参数 传递,与函数不同之处是在适当的时候能够象宏一样展开,取消甫数调用的开销,所以在C + +中应该 只使用内联函数,而不再使用宏定义。内联函数的实现
23、通常是在结构和规模比较简单的函数,如果过r复朵的函数,由多处调用多处复 制,反而会引起代码膨胀,就得不偿失了,另外内联函数不支持递归调用。2.2类和对象类是面向对象程序设计的核心,类描述了具有一组相同特性(数据成员)和相同行为(成员函数) 的对象,是对一组对象的抽象,它的实质是一种新的数据类型。通过类的结构可以规范一组对象的行为, 这些行为是通过操作接口來描述的。使用苕只需关心接1的功能,而不需耍知道它是如何实现的。所以 一个写的好的C+程序比c程序更简单,更容易理解,通常面向对象程序需要较少的手工代码,因为 问题的解决大部分都可以用已存在的库代码。2.2.1类的定义类的一般定义形式为:cla
24、ss类名pnvate:私有段数据及函数:protected:保护段数据及函数;public:公有段数据及函数:;程序清单26给出了一个点(Point)类的定义。程序演单2-6: P。i nt类的设计(一) class Pointint x;inty;public:void set_x(int k)x=k; void set_y(mt k)y=k; mt get_x() return x; mt get_y() return y;:其中Point是类名标识符。在此类中.x和y是两个私有数据成员,分别表示点的横坐标和纵坐标。 set x, set_y, get x, get_y是四个公有成员函数的
25、定义。set_x和set_y函数分别用于设置x与y,即 点的坐标值;get_x和get_y均是一个无参函数,分别返回点的坐标值。1. 成员的访问类型上述定义形式中,数据成员或成员函数前面冠以pnvate或petected或public,分别表示私有的、保 护的、公有的。觥省时在类中定义成员都是私自的,所以上例中x和y的访问类型是private。(1) pnvate私有的,是指只有类中所提供的成员西数才可以直接使用这些私有数据或调用这些私有函数,任何 类以外的函数企图去使用这些私有数据或调用这些私有函数皆将导致编译时的错误。(2) protected保护段的成员除了被本类中的成员函数存取及调用外
26、,还可以被派生类的成员函数访问。但同样不 能被其它类的函数访问。(3) public公有段的成员是可以被类内和类外的任何函数访问。一殷情况下数据成员都定义为私有的,进行封装,不允许直接使用。成员函数定义为公有的,用來 提供类与外界的操作接II,从而规范对象的行为,保护数据成员不被随意修改。而保护段成员的定义主 要是从派生类和继承性的角度來考虑的。2. 成员的组成类的成员分成两大类:数据成员和成员函数。(1) 数据成员数据成员可以是简单类型的变量,也可以是用户门定义类型的变量,甚至可以是已定义类型的一个 对象。但是不能是寄存器类型或者是外部类型,另外不能定义口身类的对象作为数据成员。(2) 成员
27、函数类的成员函数的实现可以放在类定义内,也可以放在类定义外。一般当函数体的内容较小时,成员 函数的实现放在类内,C卄编译系统将在类内实现的成员函数按内联函数來处理,可以提高执行速度, 定义时不必加inline关键字。而当函数体的大小不适合设定为inline两数时,则应将成员函数的实现放 在类外,但在类外实现的成员函数必须在类内提供函数原型。这样的类的定义分成了两个部分,即类的 定义部分和成员函数的实现部分。在VC4-4-应用程序中对类的纽织也在应分为两个文件:类的头文件 (h)存放类的定义部分,类的实现文件(*cpp)存放成员函数的实现部分.当类的成员函数的定义是在类的外部实现时,在定义方法时
28、必须把类名放在方法名之前,中间用作 用域运算符“:”隔开,用来指明其所属的类。例如程序清单2-7所示为修改上述Point类的定义:程序滴单2-7: Point类的设计(二)class Pointlilt x;inty;public:void set_x(mt k);void set_y(int k);mt get_xO;mt get_y();;void Point:set_y(mt k) 一y=k;void Point:set_x(mt k) _x=k;9VC卄6简明教程int Point: :get_x()renim x;int Point: :get_y()rehim y;从功能上來分,成
29、员函数可分为构造函数、析构函数和普通成员函数。除了析构函数不能巫我之外, 其它成员函数都能重载。2.2.2对象的定义对象的实质就是变量,对象的定义也就类似变量的定义,通常我们说对象是一个类的实例(instance) 化。遵循同样的规则,同样存在着普通对象、对象数组、对象指针和对象指针数组,以及它们的疋义和 引用。例如使用定义好的Pomt类定义一组对象:Point pl,*p, pa100,*parray100;pl是一个Point类的对象,p是一个指向Point类的对象指针,pa是 个可以/fJj攵100个point的对 象数组。对象定义后就可以访问对象中的成员,访问方法类似于C语言中结构体成
30、员的访问。不同之处是, 类的成员规定了访问类型,私有类型和保护类型的成员只能被类的成员函数访问。所以通过对象只能访 问公有数据成员和公有成员函数,如Point类中只能访问设定为公有类型的四个成员函数。成员引用的格式如下:对象名.公有数据成员名对象名.公有成员函数名(实参表)对象指针亠公有数据成员名对象指针公有成员函数名(实参表)成员引用示例如程序清单28所示.程序清单2-8:实现Point类应用的main函数#uiclude tliostreaiii.hnvoid main() Point pl,*p;mt x,y;pl.setx(lOO);pl.set_y(l(X);p=&pl;x=
31、p->get_x();y=p->get_y();cout«,x=,«x«endl«>>y=,«y«endl;J11第二帝面向对象程序设计的概念运行结果为:x=100y=1002.2.3构造函数和析构函?1. 构造函数和析构函数构造函数和析构函数是类的特殊的成员函数。展开VC + +W用程序框架中任意一个类,都可以看 到两个特纵的函数,一个完全与类名同名,是类的构造函数,另个在类名前多一个符号“”,足析构 函数.如图21所示。一个类可以看到一个或多个构造函数,但只能有一个析构函数。-cxainl 1 classe
32、s:% »«*«* "沟造用敌析构诙8(l± 叱 CAboutDIgL: B CExam1_1AppF CExam!_1Doc AoscrtValidQExam1_1DocOTExamlJDocO L)ump(CDunipContext &dcj OnNewDocumentO Serialize(CArchive &ar) l£ CExam!_1View + : CMaiiiFrame+ Q Global* 5 ClassVi. Rcsour. = FilcView图2-1类的构造怖数和析构惭数构造函数的作用是定义对象
33、时,分配内存空间,使用给定的值初始化对象。析构函数的作用恰恰相 反,在释放对象之前作一些必要的清理工作,主要清理系统分配的对象内存.构造函数的特点是它的函数名和类名相同,既可以在类内定义,也可以在类外定义;它可以有任意 类型的参数,可以巫戟,但不能有返回类型说明,即不返回任何值。析构函数的特点是它的函数名和类 名相同:前面有符,它没有参数,也没有返回值,而II也不能重载。构造函数和析构函数的调用都不需要用户干涉,当创建一个对象时,系统白动调用该类的构造函数, 当对象退出作用域时,系统自动调用该类的析构函数。若用户没有定义构造函数和析构函数,系统将口动产生缺省的构造函数和析构函数。缺省的构造函
34、数将成员变量简单的设置为0或空,缺齐的析构函数完成内存释放工作。对大多数类來说,缺省的析 构函数就能满足要求。但如果类的构造函数使用了 new分配的内存,就必须口定义一个析构函数,在析 构函数中使用delete來释放new分配的内存。而对象定义时能否进行初始化完全由构造函数决定,婆由 用户重载构造函数,指定初始化形式。2. 构造函数和对象初始化简单变量定义时,可以直接设置初值,如:mt 1=1;在定义类的成员变量时,不能在类体中对成员变量进行初始化,只能在对象定义时初始化成员变量 的值。对象的初始化实质就是调用构造丙数,耍为成员变量设初值,就要为构造丙数设定相应的形参, 在定义对象时,以实参的
35、形式传值给构造函数,构造函数就能使用给定值対成员变量设初值,方法如下:13第二帝面向对象程序设计的概念(1) 定义对象时使用函数运算符给出初值.如:Point p( 100,150);(2) 定义带参构造函数,如:Class Point nit 人 y;public:PointO;Point(int a jnt b);注意:构造函数决定对象定义的形式,一般在类定义时要给出无参构造函数,以允许在定义对象时 不进行初始化,否则,若只有带参构造函数就必须进行初始化。(3) 构造函数给成员变最赋值构造函数给成员变量賦值有两种方式,一种是直接在函数体中使用赋值语句,如:Pnmt Pomt(mt ajnt
36、 b)x=a;Y=b;另一种方式是在构造函数参数表与函数体之间,以“:”和“成员名(形参)”的方式给出,如: Point: :Point(int a,mt b):x(a),y(b)3拷贝初始化构造函数有时在创建一个对象时,希望用一个已经存在的对象來初始化这个对象,这时就需要拷贝初始化构 造函数去完成初始化工作。拷贝构造函数的作用是完成同类对象间相互拷贝。拷贝构造函数是通过一个同类型的引用参数來完成的,它的格式为:T (const T&)例如.一个Point类使用拷贝构造函数的定义和使用如下:程序清单2T:使用拷贝构造函数#mcliide "lostreani.lTclass
37、Point mt x,y;public:PouitOO;Pomt(mt a 9int b);Pomt(const Point & pa);mt g?t_x() return x;mt get_y() return y; _Point: :Pomt(int a,int b):x(a),y(b)/实现成员变量赋值Point: :Point(const Pomt& pa)/ 实现对象拷贝x=pa x;y=pay;void main()Point pl(100,150); 调用带参构造函数初始化pl Point p2(pl); 以pl的值初始化p2 cout«Hx=M
38、1;p2.get_x()«endl;cout«Hy=ft«p2.get_y()«endl;运行结果:x=100y=150拷贝构造函数的牙一个应用场合是一个数据成员是另一类的对象.对其进行初始化时.需要进行对 象拷贝,该数据成员所使用的类需要提供拷贝构造函数。例如:class T1T1 (const T1&);class T2Tla;mt x;T2 (T1 b,intx);在类T2中有一个数据成员a是T1类的对象,T2的构造甫数中,直接用一个参数值b对a进行初 始化,这就要求T1类必须提供拷贝构造函数,支持对象拷贝。2.2.4 this 指针thi
39、s是一个指向调用该成员函数的对象的常杲指针。成员函数可通过this指针直接使用同类的其它 成员,而不需要在每个成员之前加“对彖名”和成员运算符“.”。如图2-2所示,在CExaml_lView类 的成员函数OnDraw中输入this,这时this指针表加的是CExaml lX'iew类,当输入箭头时,就会弹出 个下拉列表,显示CExaml lMew类的成员供选用。图22 this指针的使用实际上,this指针在C+中纯粹是一个概念,实际编程时并不需要使用this,因为它是隐含的。理 解this指针的冃的是理解血S指针的作用,即在成员函数中使用某一数据成员时并不需要指出该数据成 员是属于
40、哪一个对象的,每一个数据成员之前都隐含有“this-”。2.2.5程序实例【例21】定义一个正方形类,该类包括:(1) 保护类数据成员,表示正方形的边长(值的范围为1-30个'"),(2) 四个成员函数,功能分别为:取边长:设置边长:画正方形:在构造该类对彖时, 初始化正方形的边长。编制main函数实现:(1) 创建一个边长为5的正方形:(2) 调用成员函数打卬正方形的形状:(3) 由用户输入正方形边长,修改边长的值:(4) 重新打印正方形。按照题目要求止方形Square类包括保护类数据成员leu,公有类成员函数:带参构造函数,収边长 函数GetLen(),设置边长函数Set
41、LenQ,画正方形函数DrawSquare()°实现代码如程序淸单210所示。程序清单2T0:实现正方形类及应用include "lostream h"class Squareprotected:mt len;public:Square。Square(int x) len=x; nit SetLen(int x);mt GetLen() return len; void DrawSquare();mt Square:SetLen(mt x)i«x<l |x>30 ) 检查x的值在l30之间retiuii 0;len=x; 设昼边长retxuu
42、 1;void Square: DrawSquareO mt i,j;fbi<i=O;i<len;i+) fdi-(j=O;j<len;j 卄) coutvv*;cout«eiidl;void main() Square s(5);cout«f,drav the square Jen=H«s.GetLeii()«endl>s DrawSquare();cout«tfinput the new side length:11;mt x;cin»x;if (!s.SetLen(x)coutWerror, length
43、 should be behveen 1 and 30! M; elsecout«Mdraxv the squareJen=M«s.GetLen()«eiidl,s DrawSquareQ;程序运行结果如下:draw the square r len=5卜XXX友X MM X3CKXXXKIinput the new side length:3 draw the square,. len=3M-X*M-M44-程序运行时定义了一个Square类的对象s,并定义边长为5个",然后调用s的成员函数GetLen 获得s的边长并输出边长信息,调用s的成员函数Dr
44、a-Squaie画出图形。允许用户输入新的正方形边长, 例如3个重复开始的输出步骤输出边长信息和图形。2.3继承继承描述的是类与类之间的关系问题。把在已有类的基础上定义新类的过程称为继承。继承的本质 是实现代码重用,因而,继承机制能缩短软件的开发周期,加快编程速度。2.3.1基类和派生类被继承的类成为基类(或父类),基J父类并增加新特性从而派生出的类称为派生类(或子类)。派 生类继承了基类中的部分或全部方法,也可修改基类中的方法,増加基类中没有的方法。定义派生类的一般格式如下:class派生类名:继承方式 基类名本派生类新定义的成员;其中,派生类名是新定义的类名:继承方式有public、pri
45、vate、protected三种,默认为pnvate方式。 继承方式决定了派生类对基类的访问性质。派生类对基类的继承情况如表2-1所示。表2-1不同继承方式下派生类对基类的访问权限继承方式基类成员访问权限派生类访问权限public(公育继承)publicpublicprotectedprotectedprivate不可访问protected(保护继承)publicprotectedprotectedprotectedpnvate不可访问pnvate(私冇继承)publicpnvateprotectedprivatepiiwte不可访问(1) public继承方式基类中的私有成员派生类不可访问,
46、不可继承,基类中其他类型的成员可以彼派生类继承,而IL继 承后的访问权限不变。(2) piotected继承方式基类中的私有成员派生类不可访问,不可继承,基类中其他类型的成员可以被派生类继承,但是继 承后的访问权限都变成保护的。(3) private继承方式基类中的私有成员派生类不可访问,不可继承,基类中其他类型的成员可以被派生类继承,但是继 承后的访问权限都变成私有的,即不可再向下派生。public继承方式揭示了父类与子类在概念上的相关性,子类应是父类的特例。当描述相关的两个实 体时,一般采用public继承方式。构造说数不能被继承,因此,派生类的构造函数必须调用某类的构造两数來初始化基类的
47、子对象。 所以,在定义派生类的构造函数时,除了对口己的数据成员进行初始化外,还必须调用基类的构造函数, 初始化基类的数抵成员°析构函数也不能觀继承.所以.执行派生类的析构函数时,基类的析构函数也 被调用,执行顺序是先执行派生类的析构函数,再执行基类的析构函数。【例22】设计两个类,一个类描述点,另一个类描述圆,圆由圆心和半径构成,圆类由点类派生而來, 其中圆心的特性描述由点类继承下來。要求圆类提供(1)衷圆而积的成员函数(2)取圆心坐标的两个 函数(3)支持初始化的带参构造函数如程序清单2-11所示,Point类为Circle类的基类,Circle类继承了 Point类的点的特性,用
48、于描述 關心,还继承取得点的坐标的两个成员函数get_x()和get_yO。Circle类在基类的基础上进行了扩展,增 加了半径的特性,并増加了四个成员函数:Circle类的构造函数的实现调用Point类的构造函数;获取圆 心坐标的两个函数get_centreX()和get_centreY(),函数的实现直接调用get_x()和get_y()实现:求圆的面 积函数Area()。程序清单2T1:派生类的实现和应用#uiclude "lostream h"class Point /定义基类int m_x, m_y;public:Pomt(int x,int y) m_x=x;
49、m_y=y; int get_x() return m_x; mt get_y() return m y;;class Circle : public Point 定义派生类,公有继承 double radius;public:Circle(mt x,mt y,double r): Pomt(x,y)/派生类没有继承基类的构适函数,而是 radius=r;通过访问基类的构造函数初始化基类的数据成员.double Area(void) return 3.14*radiiis*ra&us; 计算圆面积mt get_centreX() return get_x(); 调用基类中的成员函数访问
50、基类数据,获得 int get centreY() return get yO; 圆心坐标; void main()mt x,y;double r;cout«Hx=M; cin»x;cout«Hy=H; an»y;cout«nr=H; cm»r;Circle c(崔yj);cout«nthe centre of the Circle is H«c. get_centreX()«M and M«c. get centreYO«endl; cout«Hthe Area of th
51、e Circle is M«c.Area()«endl;运行结果:x=100y=100i-50the centre of the Circle is 100 and 100the Area of the Circle is 7850程序运行时,由用户输入圆心的坐标x,y的值及半径r的值,例如x为100, y为100,半径为5。 定义一个Circle对象c,以用户的输入值初始化这个对象。接着调用Circle类的成员函数get_centreX() 和get_centreY()输出圆心位宜,调用成员函数Area()输出圆面积。2.3.2多继承c卄允许派生类有两种方式继承基类:即单
52、继承与多继承。单继承指派生类只从一个基类派生,上 一节中的Circle类即为单继承派生类:多继承指派生类从多个基类派生,派生类几有多个基类的特性。多继承派生类的定义格式如下:class派生类名:继承方式1基类名1,继承方式n基类名n本派生类新定义的成员【例2-3】如图2-3所示,一个图形是由一个圆和一个矩形构成,要求求解图形的面积。设计三个类: 幷中两个是基类,一个施类描述圆,一个圧类描述矩形:第三个派T类是由一个圆和一个矩形构成的图 形类,如下图所示。圆类包含数据成员半径和求圆面积的成员函数,矩形类包含数据成员长和宽,求矩 形面积的成员函数。派生的图形类提供输出图形面积的西数,及支持初始化的
53、带参构造函数。19第二帝面向对象程序设计的概念#第二帝面向对象程序设计的概念矩形类穷形类2-3图形类的构成#第二帝面向对象程序设计的概念程序清单2-12;多继承示例#mclude hostream h” const double PI =3.14;class Circle 定义基类 double radius;public:Circle( double r)radiiis=r;double Circle Are a( void) retuni PI*radius*radius; 求(Ml 面枳;class Rectangle 定义基类double length,width;public:Rec
54、tangle(double x,double y)length=x>Kidth=y;double RecArea(void) return length*width; 求矩形面积class Graph public Circle,public Rectangle 定义多继承派生类public:Graph(double r,double xRouble y):Circle(r),Rectai)gle(x,y) void ShowAi-ea(void) 求图形面积,调用基类成员函数double Total Area;TotalArea= CircleArea()+RecArea();cout
55、«Hthe Area of Graph is M«TotalAi*ea«endl;void main()double x,y,r; cout«Hr=H; cin»r; cout«Hx=H; cin»x; cout«Hy=tf; cin»y; Graph g(r,x,y); g.ShowArea ();运行结果1-10x=20y=50the Area of Graph is 1314程序中定义了两个基类:Circle类表示圆类,包含一个数摒成员半径radius, 一个带参构造函数, 和一个求圆面积的成员函数
56、CircleAreaO: Rectangle类表示矩形类,包含两个数据成员长length和 width, 一个带参构造函数,和一个求矩形面积的成员函数RecAreaOo程序中定义的派生类Graph公 有继承两个基类,派生类的带参构造函数访问基类的构造函数为基类的数据成员初始化,所以两个基类 中必须捉供带参构造函数。派生类的成员函数ShowArea调用基类的公有类成员函数CircleAreaO和 RecAreaO获得圆面积和矩形而积,求出图形面积并输出。程序运行时,由用户输入圆的半径,矩形的长和宽,定义一个Graph对象g,由用户输入的数值初 始化对象go对象g调用成员函数ShowArea输出图形面积。2-4虚函数2.4.1多态性前面我们介绍了一个类中的普通成员函数的觅载,在一个继承的体系中,应该允许在派生类中对基 类的函数进行重載,这样可以在基类和派生类中使用同样的函数名而定义不同的操作,就出现了在一个 继承体系中,多个类中的函数重我。能够实现“一种接口,多种方法”的技术,就是多态性。区分不同实现的重载函数有静态联编和动态联编两种方式。静态联编的解决方式有:(1) 根据函数的参数类型和个数等参数特性的不同,來确定重载因数的归属。如:double Aiea(double radius);double Aiea(double length,double wi
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025设备租赁合同终止协议书格式模板
- 南师考古考研真题及答案
- 2025年短视频创作者合作协议(内容授权)
- 2025年新能源上市公司市值管理策略与新能源产业技术创新驱动报告
- 2025年短视频MCN转播合同协议
- 2025年十九大精神考试题及答案
- 2025年少儿主持人考级培训行业品牌建设策略报告
- 2025年棉花采摘服务行业自动化设备维护保养指南报告
- 2025-2032年中国新能源汽车出口欧盟市场政策解读报告
- 2025年工业厂房环氧地坪抗冲击性能检测技术报告
- 老年法律知识讲座
- 学堂在线 精确制导器术道 章节测试答案
- 亚当斯密管理思想
- 科学健身与健康生活大讲堂
- DB52∕T 1837-2024 党政机关办公区物业管理服务规范
- 工程劳务合作管理办法
- 国开学习网电大《化工设备使用与维护》形考任务1234答案
- 水利执法实物培训课件
- 给小学生讲建筑的课件
- 文化遗产数字化保护与旅游创新融合研究-洞察及研究
- 清平乐会昌课件
评论
0/150
提交评论