C++程序设计:第七讲 派生类_第1页
C++程序设计:第七讲 派生类_第2页
C++程序设计:第七讲 派生类_第3页
C++程序设计:第七讲 派生类_第4页
C++程序设计:第七讲 派生类_第5页
已阅读5页,还剩33页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第七讲

派生类派生类虚函数7.1派生类——从已有类中派生新的类#include<string.h>#include<iostream.h>classemployee{private:char*name;shortage;floatsalary;public:employee(){name=0;age=0;salary=0.0;}employee(char*name1,shortage1,floatsalary1){name=newchar[strlen(name1)+1];strcpy(name,name1);age=age1;salary=salary1;}

voidprint()const{cout<<“name:”<<name;cout<<“age:”<<age;cout<<“salary:”<<salary<<endl;}~employee(){delete[]name;}};Manager:除具有employee的属性外,有新的属性。为避免重复定义,可从employee中派生出manager(派生类)。派生类继承原有类中所有的数据成员和成员函数。classmanager:publicemployee{};managerm;m.print();m.salary=700.5;派生类基类使employee中所有公有成员在manager中仍为公有构造函数析构函数printPrint_levelnameagesalarylevel函数函数函数派生类新增部分基类定义部分公有方法私有成员classmanager:publicemployee{private:intlevel;public:voidprint_level(){cout<<“level:”<<level<<endl;}};protected访问指明符:外部函数不能访问;派生类成员函数可直接访问。classemployee{private:shortage;floatsalary;protected:char*name;//……};派生类成员函数:voidmanager::print_name()const{cout<<name<<endl;}外部函数:voidf(){managerm;cout<<<<endl;}派生类构造函数:使用初始化符表初始化基类中的成员。manager::manager(char*name1,shortage1,floatsalary1,intlevel):employee(name1,age1,salary1){level=level1;}缺省构造函数——若基类无缺省构造函数,将出错manager::manager(){level=0;}managerm(“wang”,31,457.2,19);构造函数析构函数printPrint_levelsalaryagenamelevel函数函数函数派生类新增部分基类定义部分公有方法私有成员保护成员函数派生类所不能继承的:编译器调用构造函数的次序:基类成员对象派生类编译器调用析构函数的次序:基类成员对象派生类7.2访问基类中的成员

类内:voidmanager::print()const{employee::print();cout<<“level:”<<level<<endl;}加作用域分辨符.不加调用当前类产生递归类外:voidmain(){employeeemp(“wang”,21,307.50);managerman(“li”,41,453.0,15);emp.print();man.print();man.employee::print();}继续派生:classdirector:publicmanager{//……}employeedirectormanager抽象、一般具体、特殊公有派生:基类所有公有成员成为派生类公有成员基类所有保护成员成为派生类保护成员classdirector:privatemanager{//……}私有派生:基类所有公有和保护成员成为派生类私有成员(缺省)classmanager:privateemployee{//……}classdirector:publicmanager{voidprint()const{cout<<“directornameis”<<name<<endl;}};classmanager:privateemployee{friendclassdirector;//……};classBase{

intm;

public:

intk;

Base(intm=0){

Base::m=m;

k=m;

}

intGetM(){

returnm;

}

};

this->m=m;classDerive:publicBase{

intn;

public:

Derive(intm=0;intn=0):Base(m){

Derive::n=n;

}

intGetN(){

returnn;

}

intSumOfMKN(){

returnGetM()+k+n;

}

};提倡成员数据书写形式:m_nBaseb;mkDerived;mkninti=d.GetM();GetM是基类Base的成员函数,对m的访问是this->m。this的类型为Base*const,是一基类指针,而这里它指向的对象是d(派生类对象)。基类指针可以指向派生类对象,而派生类指针不能指向基类对象。7.3虚函数7.3.1基类指针和派生类指针对C++中的公有派生,若把派生类对象的地址赋给基类指针,不经强制类型转换,就可以正确赋值。

classB{public:inti;floatf;};classD:publicB{public:charch;intj;};voidf(){Dd;B*b=&d;b->i=12;}

派生类地址赋给基类指针C++采用复制继承方式——派生类对象为基类所有成员分配空间(成员函数则分配函数指针空间)。jchfi基类B中的成员派生类D中新增成员派生类DbC++有两种多态性:静态多态性:操作的对象编译时确定的重载实现;动态多态性:操作的对象依赖运行的进程虚函数;//shape.h#include<iostream.h>classshape{protected:doublem_measure;public:shape(doublemeasure){m_measure=measure;}doubleArea()const{cout<<“此形状的面积无法计算”;return0.0;}};classRectangle:publicshape{doublem_width;public:Rectangle(doublelength,doublewidth):shape(length){m_width=width;}doubleArea()const{returnm_measure*m_width;}};//shape.cpp#include<shape.h>voidmain(){Rectangler(4.0,3.0);shape*p;p=&r;cout<<“面积为”<<p->Area()<<endl;}p->Area()调用shape::Area()还是Rectangle::Area()???希望根据p实际指向的对象,而不是p的类型决定调用哪个。//shape.h#include<iostream.h>classshape{protected:doublem_measure;public:shape(doublemeasure){m_measure=measure;}virtualchar*Name()const{return“二维形状”;}virtualdoubleArea()const{cout<<“此形状的面积无法计算”;return0.0;}voidShowArea()const{cout<<“所有二维形状都有面积,本”<<Name()<<“的面积是”;cout<<Area()<<endl;};//rectangle.h#include<shape.h>classRectangle:publicshape{doublem_width;public:Rectangle(doublelength,doublewidth):shape(length){m_width=width;}virtualchar*Name()const{return“矩形”;}virtualdoubleArea()const{returnm_measure*m_width;}};//triangle.h#include<shape.h>classTriangle:publicshape{doublem_height;public:Triangle(doublelength,doubleheight):shape(length){m_height=height;}virtualchar*Name()const{return“三角形”;}virtualdoubleArea()const{return0.5*m_measure*m_height;}};虚函数——特殊成员函数:编译阶段,编译器不按静态类型生成调用次函数的版本;为它生成虚函数表(存放同名,同参,同返回值的虚函数地址)。程序运行时,根据对象实际类型,查表调用相应的虚函数。classA{intk;public:A(){k=3;}virtualintGetValue(){returnk;}};classB:publicA{public:virtualintGetValue(){returnk*2;}};voidF(A*p){cout<<p->GetValue();}B*bp=newB;F(bp);A类虚函数表B类虚函数表虚函数表指针虚函数表指针虚函数表指针A类对象A类对象B类对象A::GetValue()B::GetValue()emp[i]->whoamI():1、检查emp[i]中对象类型;2、根据对象类型查虚函数表,找出相应虚函数指针;3、通过虚函数入口调用相应虚函数。注意:动态束定必须用指向基类的指针或引用(常量指针)

managerm(“wang”,42,432.5,15);employee*pe=&m;pe->whoamI();pe->employee::whoamI();employeeem=*pe;em.whoanI();employee&re=m;re.whoamI();之所以虚函数用指针或引用是为了把变量名与相应的存储单元分开。动态束定7.3.4使用虚函数classPoint{private:intx,y;public:Point(){x=0;y=0;}Point(intx_pos,inty_pos){x=x_pos;y=y_pos;}Point(constPoint&p){x=p.x;y=p.y;}intgetx(){returnx;}intgety(){returny;}};enumColorType{White,Black,Red,Green,Blue,Yellow,Magenta,Cyan};ShapeLineRectangleCircleSquareclassShape{private:ColorTypecolor;public:Shape(ColorTypec){color=c;}virtualvoiddraw(){cout<<“drawnotoverridden”<<endl;exit(1);}};classLine:publicShape{private:PointStart,End;public:Line(Points,Pointe,ColorTypec):Shape(c),Start(s),End(e){}virtualvoiddraw();};classRectangle:publicShape{private:PointupperLeft,lowerRight;public:Rectangle(Pointul,Pointlr,ColorTypec):Shape(c),upperLeft(up),lowerRight(lr){}virtualvoiddraw();};classCircle:publicShape{private:Pointcenter;intradius;public:Circle(Pointctr,intr,ColorTypec):Shape(c),center(ctr){radius=r;}virtualvoiddraw();};classSquare:publicRectangle{public:Square(Pointul,intl,ColorTypec):Rectangle(ul,Point(ul.getx()+l,ul.gety()+l),c){}};

classPicture{private:Shape*s[6];public:Picture(Shape*s1,Shape*s2,Shape*s3,Shape*s4,Shape*s5,Shape*s6){s[0]=s1;s[1]=s2;s[2]=s3;s[3]=s4;s[4]=s5;s[5]=s6}voidpaint(){for(inti;i<6;++i)s[i]->draw();}};intmain(){Linel1(Point(1,1),Point(250,300),Red);Circlec1(Point(100,75),50,Blue);Circlec2(Point(50,200),20,Green);Rectangler1(Point(10,10),Point(225,150),Yellow);Rectangler2(Point(300,30),Point(30,125),Magenta);Squares1(Point(150,150),50,White);Picturep(&l1,&c1,&r1,&s1,&c2,&r2);

p.paint();return0;}7.3.5与虚函数相关的特征●抽象基类基类中虚函数没定义,用初始化符=0代替函数定义,这时的虚函数叫

纯虚函数。classX{//……public:virtualvoidprint()=0;//……};含有纯虚函数的类叫做抽象基类。classY{public:virtualvoidprint(){};//……};Xx1;Yy1;只能作为别的类的基类,不能生成抽象基类的对象●虚析构函数(构造函数可以是虚函数吗?)classX{private:char*p;public:X(intsize){p=newchar[size];}virtual~X(){delete[]p;}};classY:publicX{private:char*pp;public:Y(intsz1,intsz2):X(sz1){pp=newchar[sz2];}~Y(){delete[]pp;}};

自动成为虚函数调用Y::~Y()删除Y::pp调用X::~X()删除X::pX*px=newY(10,12);//……deletepx;函数名返回值参数束定时间适用范围语义相关性虚函数同同运行时派生类一组类似函数重载函数可不同不同编译时任意可语义无关●虚函数和重载函数一组虚函数中,两个虚函数仅返回值不同,参数和名字相同,编译错。派生类虚函数的参数与基类虚函数参数不同,则不属于同一组虚函数,是重载关系。classNumber{public:virtualvoidadd(int);//……};classBigNumber:publicNumber{public:virtualvoidadd(double);//……};voidmain(){BigNumberb0;Number*a=&b0;BigNumber*b=&b0;a->add(1);a->add(3.0);b->add(2);b->add(2.0);b->Number::add(9);}基类指针不能动态束定,派生类指针覆盖基类函数7.4多继承temporarytemporary::print_it()employeeemployee::whoamI()consultantconsultant::print_it()consultant::whoamI()managermanager::whoamI()directordirector::whoamI()两个以上直接基类

classconsultant:publicmanager,publictemporary{//……};

consultantcon;manager*pm=&con;employee*pe=&con;temporary*pt=&con;pm->whoamI();pe->whoamI();pt->whoamI();pt->print_it();consultant的构造函数:consultant::consultant(char*name1,intage1,floatsalary1,intlevel1,floatapsalary1,intday1):manager(name1,age1,salary1,level1),temporary(day1){apsalary=apsalary1;};问题:classA{public:inta;voidf();};classB{public:inta;voidf();};classC:publicA,publicB{//……};

Ccobject;cobject.a=10;cobject.f();重新定义类C:classC:publicA,publicB{public:inta;voidf();//……};Ccobject;cobject.a=10;cobject.f();cobject.A::a=10;7.5重复继承和共享继承重复继承QueueMessageMenuMenu_MessageQueue保存基类两个以上的拷贝——重复继承print()Queue*pq=(Message*)&mm;二义性:Menue_Messagemm;mm.print;mm.Queue::print();Queue*pq=&mm;EditWindowPictureWindowWindowEdit_Picture_WindowWindow的成员由EditWindow和PictureWindow共享虚基类(共享继承解决一致性和冗余)

classEditWindow:publicvirtualWindow{//……};classPictureWindow:publicvirtualWindow{//……};classEdit_Picture_Window:publicEditWindow,publicPictureWindow{//……};注意:仍有二义性问题练习题:1、写出程序运行结果#include<iostream.h

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论