一5多态与虚函数_第1页
一5多态与虚函数_第2页
一5多态与虚函数_第3页
一5多态与虚函数_第4页
一5多态与虚函数_第5页
已阅读5页,还剩38页未读 继续免费阅读

下载本文档

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

文档简介

C++语言程序设计第5章多态性与虚函数本章主要内容重载静态关联与动态关联虚函数纯虚函数与抽象类虚析构函数

§5.1重载在类中,构造函数可以重载,普通成员函数也可以重载;构造函数重载给初始化带来了多种方式,为用户提供了更大的灵活性。一、函数重载二、运算符重载的几个问题1、哪些运算符可以重载?算术运算符:+、-、*、/、%、++、--;位操作运算符:&、|、~、^、<<、>>;逻辑运算符:!、&&、||;比较运算符:>、<、>=、<=、==、!=;赋值运算符:=、+=、-=、*=、/=、%=、

&=、|=、~=、<<=、>>=;其他运算符:[]、()、->、'

、new、delete、

new[]、delete[]、->*;不允许重载的运算符:.、*、::、?:、sizeof;2、编译程序如何选用哪一个运算符函数?运算符实质上是函数,遵循函数重载原则;3、运算符重载时必须遵循哪些原则?重载运算符含义必须清楚;重载运算符不能有二义性;4、重载运算符有哪些限制?不可臆造新的运算符;重载运算符坚持4个“不能改变”:不能改变运算符操作数的个数;不能改变运算符原有的优先级;不能改变运算符原有的结合性;不能改变运算符原有的语法结构;函数类型operator运算符名称(形参表列){对运算符的重载处理}其参数中至少有一个为类对象或类对象的引用。

三、运算符重载函数一般格式四、运算符重载函数的两种形式1、重载为类的成员函数重载一元运算符,不再显式说明参数;重载二元运算符,只显式说明一个参数;该参数为操作数的右操作数,左操作数由this指针(指向调用该成员函数的对象)提供;重载为成员函数时,隐含了一个参数(this指针);[例]分析下列程序的输出结果。#include<iostream.h>classcomplex{public:

complex(doubler=0,doublei=0);

complexoperator+(constcomplex&c);

complexoperator-(constcomplex&c);

complexoperator-();voidprint()const;private:doublereal,imag;};complex::complex(doubler,doublei){+运算符-运算符求负运算符

real=r;

imag=i;}complexcomplex::operator+(constcomplex&c){doubler=real+c.real;doublei=imag+c.imag;returncomplex(r,i);}complexcomplex::operator-(constcomplex&c){doubler=real-c.real;doublei=imag-c.imag;returncomplex(r,i);}complexcomplex::operator-(){returncomplex(-real,-imag);}voidcomplex::print()const{

cout<<'('<<real<<','<<imag<<')'<<endl;}voidmain(){complexc1(2.5,3.7),c2(4.2,6.5);complexc;c=c1-c2;c.print();c=c1+c2;c=c1.operator-(c2);c=c1.operator+(c2);

c.print();c=-c1;c.print();}输出

(-1.7,-2.8)

(6.7,10.2)

(-2.5,-3.7)c=c1.operator-();2、重载为友元函数重载为友元函数时,没有隐含的参数this指针,即不改变原有运算符的语法结构;重载为友元函数的运算符重载函数的格式:friend<类型说明符>operator<运算符>(<参数表>){……}[例]分析下列程序的输出结果。#include<iostream.h>classcomplex{public:

complex(doubler=0,doublei=0);friendcomplexoperator+(constcomplex&c1,constcomplex&c2);

friendcomplex

operator-(constcomplex&c1,constcomplex&c2);

friendcomplexoperator-(constcomplex&c);voidprint()const;private:doublereal,imag;};+运算符-运算符求负运算符complex::complex(doubler,doublei){real=r;

imag=i;}complexoperator+(constcomplex&c1,constcomplex&c2){doubler=c1.real+c2.real;doublei=c1.imag+c2.imag;returncomplex(r,i);}complexoperator-(constcomplex&c1,constcomplex&c2){

doubler=c1.real-c2.real;doublei=c1.imag-c2.imag;returncomplex(r,i);}complexoperator-(constcomplex&c){returncomplex(-c.real,-c.imag);}voidcomplex::print()const{

cout<<'('<<real<<','<<imag<<')'<<endl;}voidmain(){complexc1(2.5,3.7),c2(4.2,6.5);

complexc;c=c1-c2;c.print();c=c1+c2;c.print();c=-c1;c.print();}输出

(-1.7,-2.8)

(6.7,10.2)

(-2.5,-3.7)c=operator-(c1,c2);c=operator+(c1,c2);c=operator-(c1);3、两种重载形式的比较一般情况下,单目运算符最好重载为成员函数;双目运算符则最好重载为友元函数;如果重载为成员函数,必须要求运算表达式第一个参数是类对象,且与运算符函数类型相同。如果重载为友员函数,必须有两个形参,不能省略。多态性:发出同样的消息被不同类型的对象接受导致完全不同的行为;多态可分为:静态多态性与动态多态性;动态多态性必须存在于继承的环境之中;多态性的概念概念:静态关联:在编译时进行的关联,即编译时就确定了程序中的操作调用与执行该操作代码之间的关系。关联:确定调用具体对象的过程。(把一个标识符和一个地址联系起来)§5.2静态关联和动态关联动态关联:在程序执行时进行的关联;实现:C++动态关联在虚函数的支持下实现;§5.3虚函数1、虚函数虚函数是动态关联的基础;virtual<类型说明符><函数名>(<参数表>)说明方法:含义:若类中一成员函数被说明为虚函数,则该成员函数在派生类中可能有不同的实现。当使用该成员函数操作指针或引用所标识的对象时,对该成员函数调用可采用动态关联方式。[例]分析下列程序的输出结果。#include<iostream.h>classPoint{public:Point(doublei,doublej){x=i;y=j;}

virtualdoubleArea()const{return0;}private:doublex,y;};classRectangle:public

Point{public:

Rectangle(int

i,int

j,int

k,intl);

virtualdoubleArea()const{returnw*h;}private:虚函数虚函数

doublew,h;};Rectangle::Rectangle(int

i,int

j,int

k,intl):Point(i,j){w=k;h=l;}voidfun(Point&s){

cout<<s.Area()<<endl;}voidmain(){

Rectanglerect(3.0,5.2,15.0,25.0);

fun(rect);}输出:

375[例]分析下列程序的输出结果,并回答问题。#include<iostream.h>classA{public:

virtual

voidact1()

{cout<<"A::act1()called."<<endl;}voidact2(){act1();}};classB:publicA{public:

voidact1(){cout<<"B::act1()called."<<endl;}};公有继承,B是A的子类型虚函数voidmain(){Bb;b.act2();}回答下列问题:(1)、该程序执行后的输出结果是什么?为什么?输出结果为:B::act1()called.原因:a.B从A公有继承,B是A的子类型;

b.B中的act1()为虚函数;

c.b.act2()调用A中的act2(),进一步调用act1(),产生动态关联,运行时选择B::act1();为什么?(2)、如果将A::act2()的实现改为:

voidA::act2()

{

this->act1();

}

输出结果是什么?为什么?输出结果与(1)相同,即:B::act1()called.原因:this指向操作该成员函数的对象,基于与(1)相同的原因,此处调用B::act1()。(3)、如果将A::act2()的实现改为:

voidA::act2()

{

A::act1();

}

输出结果是什么?为什么?输出结果:A::act1()called.原因:此处增加了成员名限定,因此要进行静态关联,即调用的是A::act1()。派生类中对基类的虚函数进行替换时,要求派生类中说明的虚函数与基类中的被替换的虚函数之间满足下列条件:参数个数:与基类的虚函数有相同的参数个数;参数类型:与基类的虚函数的对应参数类型相同;返回值类型:与基类的虚函数的返回值类型相同;满足上述条件的派生类虚函数,可不加virtual说明。§5.4纯虚函数1、引入在基类中不能为虚函数给出一个有意义的实现时,可将其声明为纯虚函数,其实现留待派生类完成;2、作用为派生类提供一个一致的接口;3、声明格式

class<类名>

{

virtual<类型><函数名>(<参数表>)=0;

……

}[例]分析下列程序的输出结果。#include<iostream.h>classPoint{public:

Point(inti=0,intj=0){x0=i;y0=j;}

virtual

voidSet()=0;virtualvoidDraw()=0;protected:

intx0,y0;};classLine:publicPoint{public:

Line(inti=0,intj=0,intm=0,intn=0):Point(i,j){x1=m;y1=n;}voidSet(){cout<<"Line::Set()called."<<endl;}voidDraw(){cout<<"Line::Draw()called."<<endl;}protected:

intx1,y1;};classEllipse:publicPoint{public:

Ellipse(inti=0,intj=0,intp=0,intq=0):Point(i,j){x2=p;y2=q;}

voidSet(){cout<<"Ellipse::Set()called."<<endl;}

voidDraw(){cout<<"Ellipse::Draw()called."<<endl;}protected:

intx2,y2;};voidDrawObj(Point*p){p->Draw();}voidSetObj(Point*p){p->Set();}voidmain(){Line*lineobj=newLine;Ellipse*ellipseobj=newEllipse;

DrawObj(lineobj);

DrawObj(ellipseobj);

cout<<endl;

SetObj(lineobj);

SetObj(ellipseobj);

cout<<endl<<"Redrawtheobject…"<<endl;

DrawObj(lineobj);

DrawObj(ellipseobj);}

Line::Draw()called.

Ellipse::Draw()called.

Line::Set()called.

Ellipse::Set()called.

Redrawtheobject...

Line::Draw()called.

Ellipse::Draw()called.执行结果§5.5抽象类带有纯虚函数的类称为抽象类;抽象类只能作为基类使用,其纯虚函数的实现由派生类给出;但派生类仍可不给出纯虚函数的定义,继续作为抽象类存在;抽象类不能定义对象,一般将该类的构造函数说明为保护的访问控制权限;抽象类的作用:用作基类:在一个继承层次结构中,提供一个公共的根,并基于抽象类的操作设计出对抽象类所描述的一类对象进行操作的公共接口,其完整的实现由派生类完成;用作指针或引用的基类型:保证进入继承层次的每个类都具有(提供)纯虚函数所要求的行为;在成员函数内可以调用纯虚函数,但在构造函数或析构函数内不能调用纯虚函数(纯虚函数没有实现代码);

classA

{

public:

virtual

voidf()=0;

voidg(){f();}

A(){f();}

}正确错误§5.6虚析构函数虚析构函数

在析构函数前加关键字virtual进行说明,则该析构函数称为虚析构函数;格式:

classB

{

public:

virtual

~B();

…...

}如果一个类的析构函数被说明为虚析构函数,则它的派生类中的析构函数也是虚析构函数,不管它是否使用了关键字vi

温馨提示

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

评论

0/150

提交评论