版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
2.11.3多(重)继承C++中,从一个基类派生的继承称为单(一)继承或。从多个基类派生的继承称为多(重)继承。见下图所示。类A派生类B类X和类Y派生类Z
(a)单继承(b)多继承多继承定义格式:class派生类名:访问权限基类名1,访问权限基类名2[,…]{新增加的成员};ABXYZA
B1例:build是一个房屋数据类,buisiness是建筑单位数据类。以二者为基类按公有方式派生出工程类proj。proj将两个基类的全部成员按原有方式继承下来。程序清单:#include<iostream.h>#include<windows.h>//或<string.h>classbuild//定义房屋数据类{protected: intposi_x;//房屋的经度 intposi_y;//房屋的纬度 intarea;//房屋的面积buildbusinessproj2public: voidset1(intx,inty,inta) { posi_x=x;posi_y=y;area=a; }};classbusiness//定义建筑单位数据类{protected: char*business_name;//施工单位public: voidshow() { cout<<"施工单位:"<<business_name<<endl; }
3voidset2(char*str) { strcpy(business_name,str); }};classproj:publicbuild,publicbusiness{private: inthigh;//房屋的高度public: voidset3(inth) { high=h; }4
voiddisp() { cout<<"经度:"<<posi_x<<endl; cout<<"纬度:"<<posi_y<<endl; cout<<"高度:"<<high<<endl; cout<<"面积:"<<area<<endl; }};voidmain(){ projobj; obj.set1(100,200,300);//调用build类的成员函数 obj.set2("武建集团");//调用business类的成员函数 obj.set3(400);//调用proj类的成员函数 obj.disp();//调用proj类的成员函数 obj.show();//调用business类的成员函数}5运行结果:经度:100纬度:200高度:400面积:300施工单位:武建集团C++关于类的继承的规定:⑴私有继承方式:基类中的公有成员和保护成员在派生类中皆变为私有成员。⑵公有继承方式:基类中的公有成员和保护成员在派生类中不变。⑶保护继承方式:基类中的公有成员和保护成员在派生类中皆变为保护成员。⑷无论哪种继承方式,私有成员皆不能被继承。6
当一个类从它的基类中继承一部分成员后,这个类还可以将自己继承的成员再继承给其它的类,这种继承的可传递性称作的“多层继承”(见下图),与生物繁衍过程的遗传特性十分相似。
图:多层继承示意图
ABC基类72.12对象引用作函数参数2.12.1对象指针作函数参数使用对象指针作为函数参数要比使用对象作函数参数更为普遍。因为使用对象指针作函数参数有两点好处:⑴
实现传址调用可在被调用函数中改变调用函数的参数对象的值,实现函数之间的信息传递。⑵使用对象指针实参仅将对象的地址值传给形参,而不进行副本的拷贝,这样可以提高运行效率,减少时空开销。对象指针作函数形参时要求调用函数的实参是对象的地址值(一般用&对象名)。
8例:指向对象的指针作函数参数的调用方法——分析程序输出结果。//obj_ptr.cpp#include<iostream.h>classM{public: M(){x=y=0;} M(inti,intj){x=i;y=j;} voidcopy(M*m); voidsetxy(inti,intj){x=i;y=j;} voidprint(){cout<<x<<","<<y<<endl;}private: intx,y;};9voidM::copy(M*m){ x=m->x; y=m->y;}voidfun(Mm1,M*m2)//m1:对象名作形参,m2:对象指针名作形参{ m1.setxy(12,15); m2->setxy(22,25);}voidmain(){ Mp(5,7),q; q.copy(&p); fun(p,&q); p.print(); q.print();}10运行结果:5,722,25
实参用对象地址值:&对象名,形参用指向对象的指针名。1.~3.句执行情况:1.Mp(5,7),q;p.x=5,p.y=7;q.x=0,q.y=0.2.q.copy(&p);q.x=5,q.y=7;3.fun(p,&q);q.x=22,q.y=25;112.12.2对象引用作函数参数在实际工作中,使用对象引用作函数参数比使用对象指针作函数参数更普遍。这是因为使用对象引用作函数参数具有对象指针作函数参数的优点,并且用对象引用作函数参数将更简单、更直接。因此,C++程序员喜欢用对象引用作函数参数。例:分析下面程序输出结果。//obj_ref.cpp#include<iostream.h>classM{public: M(){x=y=0;} M(inti,intj){x=i;y=j;} voidcopy(M&m);12 voidsetxy(inti,intj){x=i;y=j;} voidprint(){cout<<x<<","<<y<<endl;}private: intx,y;};voidM::copy(M&m){ x=m.x; y=m.y;}
13voidM::copy(M&m){ x=m.x; y=m.y;}voidfun(Mm1,M&m2){ m1.setxy(12,15); m2.setxy(22,25);}14voidmain(){ Mp(5,7),q; q.copy(p); fun(p,q); p.print(); q.print();}运行结果(与上例相同):5,722,25
实参用对象名,形参用对象引用名。说明:本例程序与前面程序主要区别在于把使用指向对象的指针换成了对象引用。试比较一下指针与引用在使用上的区别。152.13this指针this是隐含于每一个类的成员函数中的特殊指针。
简言之,this是指向“当前对象”的指针。通过该指针可以确定哪个对象的成员被引用。每次成员函数存取数据成员时,则隐含使用this指针。同样也可使用*this来标识调用该成员函数的对象。例:显示this指针的值。程序清单:#include<iostream.h>classA{private:intx,y;public:
16A(inti,intj){x=i;y=j;}voidget(){cout<<"\nthis="<<this<<"whenx="<<x<<endl;}};voidmain(){Aa(1,1),b(2,2),c(3,3);a.get();b.get();c.get();}17运行结果:this=0x0065FDF0whenx=1//a对象的地址this=0x0065FDE8whenx=2//b对象的地址this=0x0065FDE0whenx=3//c对象的地址例:分析下列程序输出结果,说明程序中this和*this的用法。程序清单:#include<iostream.h>classA{public: A(){a=b=0;} A(inti,intj){a=i;b=j;} voidcopy(A&aa);18 voidprint() {cout<<a<<","<<b<<endl;}private: inta,b;};voidA::copy(A&aa){ if(this==&aa)return;
*this=aa;//this指针指向对象a1
//此句也可写成两句:this->a=aa.a;this->b=aa.b;}19voidmain(){Aa1,a2(3,4);//1.a1.copy(a2);//2.a1.print();//3.}运行结果:3,4分析:本程序中,this是操作该成员函数对象的地址;*this是操作该成员函数的对象,而*this=aa;//*this:this所指向的对象它表示将形参获得的某对象的值赋给操作该成员函数的对象。在本例中,操作该成员函数的对象为a1。201.~3.句执行的情况:1.a1.a=0,a1.b=0;a2.a=3,a2.b=4;2.(1)aa.a=3,aa.b=4;(2)if(this=&aa)return;this=&a1,&aa=&a2故this≠&aa(条件不满足,执行后续语句)(3)*this=aa;aa.a→a1.a,aa.b→a1.b3.显示a1.a和a1.b;212.14多态性多态性(polymorphism)是指一个接口的名称具有多种功能。在面向对象的三大基本特征中,封装性是基础,继承性是关键,多态性是补充。多态性有两种类型:1、重载(函数重载,运算符/操作符重载),2、虚拟函数重载(overloading:包括函数重载和操作符重载)属于程序编译时的多态性;虚拟函数(virtualfunction)属于程序运行时的多态性。2.14.1函数重载函数重载(functionoverloading)是指两个或两个以上的函数取相同的名字,而使用不同类型或不同数目的参数。使用函数重载可以减轻用户的记忆负担,并使程序结构简单、易懂。C++的构造器可以重载,另外,用户还可在程序中定义其它重载函数。例:P69[例Ex_OverLoad]编程求两个或三个操作数之和。222.14.2操作符重载操作符重载(operatoroverloading)是指将已有的操作符/运算符赋予新的功能。可把操作符重载看成类的成员函数,称为操作符重载成员函数。操作符重载成员函数定义格式:类型[类名::]operator操作符(参数表){函数体}其中,operator是用于定义操作符重载函数的关键词。操作符重载成员函数定义在类内时,[类名::]省略不写。C++中,操作符可以是三种通用的操作符:算术运算符、逻辑运算符和位运算符。可以将所有的三种类型的操作符重载,让它们去完成程序员需要的动作而取代其默认情况下的操作。23例:重载“+”运算符实现两个时间相加。程序清单:#include<iostream.h>classMytime{private: inthour; intmin; intsec;public: Mytime() { hour=min=sec=0; }//构造器124
Mytime(inth1,intm1,ints1) { sec=s1%60; m1=m1+s1/60; min=m1%60; h1=h1+m1/60; hour=h1%24; }//构造器2(将时、分、秒转换成相应进制的数)
Mytimeoperator+(MytimeT1){ MytimeT2(hour+T1.hour,min+T1.min,sec+T1.sec); returnT2;}//操作符重载成员函数25voidPrintMytime() { cout<<"Time:"; cout<<hour; cout<<':'<<min; cout<<':'<<sec<<’\n’; }};//定义时间类voidmain(){ Mytimet1(3,30,29);//1. Mytimet2(4,25,38);//2. Mytimet3;//3. t3=t1+t2;//4. t3.PrintMytime();}26运行结果:Time:7:56:7程序标号1.~3.句的说明:1.生成对象t1,调用构造器2初始化对象t1t1.hour=3,t1.min=30,t1.sec=292.生成对象t2,调用构造器2初始化对象t2t1.hour=4,t1.min=25,t1.sec=383.生成对象t3,调用构造器1初始化对象t3t1.hour=0,t1.min=0,t1.sec=04.用“+”重载操作符实现时间相加运算编译程序将t1+t2解释为:
t1.operator+(t2)其中,t1和t2是Mytime类的对象。operator+()是操作符“+”的重载函数。27这里操作符重载函数仅有一个参数。即:当重载为类的成员函数时,操作符重载函数的形参个数要比操作符操作数个数少一个(教材P91页12行)。时间相加执行过程分析:(1)
把t2对象的值传给operator+()成员函数的T1对象T1.hour=4,T1.min=25,T1.sec=38(2)
执行MytimeT2(hour+T1.hour,min+T1.min,sec+T1.sec);此句中,hour等价于this->hour, min等价于this->min,sec等价于this->sec;而执行此句时,this指向t1对象,故:hour实为t1.hour,min实为t1.min,sec实为t1.sec;相加后:T2(7,55,67);执行构造器2后:T2(7,56,7)构造器2所完成的功能:将分和秒转换成60以内的数,将小时转换成24以内的数。(3)
执行returnT2;返回T2传给主函数t3。28不能重载的操作符有::?——三目操作符.——成员运算符::——作用域操作符->——指向运算符sizeof()——sizeof()运算符29例:用操作符重载成员函数编写V1和V2两向量相加的程序。//ex_opovld.cpp:运算符重载为类的成员函数#include<iostream.h>classV_sum{private: floatx,y;public: V_sum() { x=y=0; }30 V_sum(floata,floatb) { x=a;y=b; } V_sumoperator+(V_sumu1); //运算符重载为类的成员函数,形参个数比运算符操作数个数少一个 voidV_output();};V_sumV_sum::operator+(V_sumu1){ V_sumu2(this->x+u1.x,this->y+u1.y); returnu2;}31voidV_sum::V_output(){ cout<<"V3=("<<x<<","<<y<<")"<<endl;}voidmain(){ V_sumV1(1,5),V2(8,3),V3; V3=V1+V2;//编译器将V1+V2解释成V1.operator+(V2) V3.V_output();}322.14.3虚函数虚函数(virtualfunction)是指某个函数在基类中被定义为virtual,而在派生类中又重新定义了该函数。虚函数是实现动态联编的基础。联编是指一个计算机程序自身彼此关联的过程。按照联编所进行的阶段不同,可分为两种联编方法:静态联编和动态联编。程序在编译时进行联编工作被称为静态联编,或称为静态束定。程序在运行时进行联编工作被称为动态联编,或称为动态束定。
虚函数定义格式:virtual函数类型函数名(参数表){函数体}
虚函数必须存在于继承的环境中。33程序例:#include<iostream.h>classcA//定义基类{public: doubleA(doublex) { returnx*x; } doubleB(doublex) { returnA(x)/2; }};34classcB:publiccA//定义cA的派生类{public: doubleA(doublex) { returnx*x*x; }};voidmain(){ cBobj; cout<<obj.B(3)<<endl;}35运行结果:4.5(而不是13.5?)意图:cA:BCALLcB::A实际:cA:BCALLcA::A,而cB::A弃而不用注:cA:B——cA类继承下来的函数BcB::A——类cB中的函数A
该程序的输出是4.5,而不是13.5!为什么?回答是基于这样一个事实,那就是程序执行obj.B(3)时使用的是继承函数cA:B,而接下来cA:B调用的却是函数cA::A。这样函数cB::A被搁置在一边弃而不用,程序未能支持多态性的行为。
36例:现在上例的类cA和类cB的A函数前加virtual,重写程序(该程序表明虚函数是怎样成功地在类cA和类cB中完成多态性行为的)。#include<iostream.h>classcA//定义基类{public:
//定义虚函数,在基类中必须加关键词virtual
virtualdoubleA(doublex) { returnx*x; } doubleB(doublex) { returnA(x)/2; }};
37运行结果:13.5cA:BCALLcB::A(从类cA继承下来的函数B调用类cB中定义的函数A)一旦说明一个函数是虚函数,则只能用子孙类中的函数来超越。超越和被超越的函数必须相同的参数表和返回类型。虚函数的特性:一旦为虚总为虚(即虚函数具有继承性)。例:教材P87[例Ex_VirtClass]。382.15友元函数类的重要特性是使数据封装与隐藏,但同时也给外部函数访问类中的私有和保护数据成员带来了不便,为此,C++提供了友元函数来解决这个问题。友元函数(friendfunction:简称友元)可以存取类的私有成员、保护成员和公有成员。类的友元函数是类的接口的一部分,但它不是
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 光伏电站建设技术方案
- 2024设备安全协议合同
- 2024个人房屋租赁合同书参考
- 2024围网围栏工程分包合同
- 2024存量房买卖合同存量房买卖合同
- 无人驾驶技术应用方案
- 商业中心绿色经营规章
- 线上教育健康管理方案
- 安徽省芜湖市2023-2024学年高一上学期期末考试 英语 含答案
- 平面设计软件训练学习通超星期末考试答案章节答案2024年
- 中国心力衰竭诊断和治疗指南2024十大要点解读
- 国开2024年秋《机电控制工程基础》形考任务2答案
- 生猪屠宰兽医卫生检验人员理论考试题及答案
- 一年级拼音默写表
- 2024年黑龙江省机场管理集团有限公司招聘笔试参考题库含答案解析
- 小学各年级“红领巾奖章”获章标准
- 河北省沧州市药品零售药店企业药房名单目录
- 小学四年级上册数学综合实践活动计划
- 第七章气相色谱法PPT课件
- 金蝶ERP流程图
- 钢结构工程旁站方案.doc
评论
0/150
提交评论