您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > c++程序设计第八章多态性和虚函数
1第八章多态性和虚函数本章考核要求:1、理解多态性的概念,达到“领会”层次。2、了解静态联编和动态联编所支持的多态性,达到“识记”层次;3、掌握虚函数的定义方法,达到“简单引用”层次;4、理解虚函数实现多态性的条件,达到“领会”层次;5、熟练掌握构造函数和析构函数调用虚函数,达到“综合应用”层次;6、熟练掌握纯虚函数与抽象基类,达到“综合应用”层次、28.1多态性函数重载函数默认参数函数模板不同的对象可以调用相同名称的函数,但可导致完全不同的行为的现象称为。多态性此前学习过的多态性:类模板虚函数是c++实现多态性的另一种重要机制。3C++支持两种多态性,即编译时的多态性和运行时的多态性。编译时的多态性:在编译阶段由编译器根据函数调用时所使用的实参就确定下来应调用哪个函数。由静态联编支持。即静态联编所支持的多态性称为编译时的多态性。运行时的多态性:在执行阶段依据要处理的对象类型来决定执行哪个类的成员函数。由动态联编支持。即动态联编所支持的多态性称为运行时的多态性。由虚函数支持。4通过指向对象的指针或引用调用成员函数时:所调用成员函数为指针和引用所属类的成员函数一、静态联编中的赋值兼容性和名字支配规律类的对象与该对象调用的函数一一对应,程序编译时即可确定该对象调用哪一个函数,5例题:分析以下程序运行结果(lt8_1.cpp)#includeiostreamusingnamespacestd;constdoublePI=3.14;classPoint{doublex,y;public:Point(doublea,doubleb){x=a;y=b;}doublearea(){return0;}};classCircle:publicPoint{doubleradius;public:Circle(doublea,doubleb,doubler):Point(a,b){radius=r;}doublearea(){returnPI*radius*radius;}};voidmain(){Pointa(1.5,2.5);Circleb(1.5,2.5,5);cout点的面积:a.area()endl;cout圆的面积:b.area()endl;Point&ra=b,*pa=&b;coutra.area(),pa-area()endl;Circle&rb=b,*pb=&b;coutrb.area(),pb-area()endl;}基类的指针(引用)只能指向基类,派生类指针(引用)只能指向派生类,它们的原始类型决定它们只能调用各自的同名函数名字支配规律决定它们调用各自的同名函数。6动态连编的多态性是指当程序执行时才能确定指针或引用所调用的成员函数是基类的还是派生类的成员函数,在编译时仅检查函数调用是否符合赋值兼容规则。要实现程序运行时决定指针所调用的函数是基类的还是派生类的,即:动态联编。二、动态联编的多态性7voidmain(){Circleb(1.5,2.5,5);Point&ra=b,*pa=&b;coutra.area(),pa-area()endl;}例题:分析以下程序运行结果(lt8_1.cpp)#includeiostreamusingnamespacestd;constdoublePI=3.14;classPoint{doublex,y;public:……doublearea(){return0;}};classCircle:publicPoint{doubleradius;public:……doublearea(){returnPI*radius*radius;}};如果使程序输出下图?virtual用关键词virtual声明的函数称为虚函数9虚函数是动态联编的基础,它是引入派生概念之后用来表现基类和派生类成员函数之间的一种关系。虚函数在基类中定义,也是一种的成员函数,且不能是静态成员函数。构造函数不可定义为虚函数析构函数可定义为虚函数8.2虚函数一旦基类中定义了虚函数,则该类的派生类中的同名函数(函数返回值类型、函数参数也相同)自动为虚函数。调用规则:根据当前对象,优先调用对象本身的虚函数。10如:ClassA{Public:virtualvoidf(){…………}};ClassB:publicA{Public:voidf(){………}};形式:virtual函数类型函数名(参数表)注:当在派生类中定义了一个同名的成员函数时,只要该函数的参数个数、类型及返回类型与基类中同名的虚函数完全一样,则无论是否使用virtual关键字,都自动成为一个虚函数。一、虚函数的定义:11voidmain(){Pointa(1.5,2.5);Circleb(1.5,2.5,1);Point&ra=b,*pa=&b;coutra.area(),pa-area()endl;coutra.Point::area(),pa-Point::area()endl;couta.area(),b.area()endl;}例题:分析以下程序结果(lt8_2a.cpp)#includeiostreamusingnamespacestd;constdoublePI=3.14;classPoint{doublex,y;public:Point(doublea,doubleb){x=a;y=b;}virtualdoublearea(){return0;}};classCircle:publicPoint{doubleradius;public:Circle(doublea,doubleb,doubler):Point(a,b){radius=r;}doublearea(){returnPI*radius*radius;}};使用虚函数并不一定产生多态性,也不一定使用动态联编12二、虚函数实现多态性的条件例如:假设基类A中定义了虚函数f在派生类B中重定义了函数f则:使用虚函数并不一定产生多态性,也不一定产生动态联编。在调用虚函数中使用成员名限定,可以强制c++对函数的调用使用静态联编。如上例中的:coutra.Point::area(),pa-Point::area()endl采用一般类型的对象调用虚函数,则采用静态联编,如上例中的couta.area(),b.area()endl;13产生运行时多态的条件(动态联编):1,类之间的继承关系满足赋值兼容规则2,派生类中重定义了同名虚函数3,根据赋值兼容规则使用指针或引用(必备条件)2)用基类引用(基类指针)作函数形参参数时,函数调用时用派生类对象(或地址)做实参条件3有两种形式:1)利用指向派生类的基类指针调用虚函数利用引用了派生类对象的基类引用调用虚函数14例题:分析以下程序结果(lt8_2.cpp)#includeiostreamusingnamespacestd;constdoublePI=3.14;classPoint{doublex,y;public:Point(doublea,doubleb){x=a;y=b;}virtualdoublearea(){return0;}};classCircle:publicPoint{doubleradius;public:Circle(doublea,doubleb,doubler):Point(a,b){radius=r;}doublearea(){returnPI*radius*radius;}};voiddisp(Point*p){coutp-area()endl;}voiddisp(Point&a){couta.area()endl;}voidmain(){Pointa(1.5,2.5);Circleb(1.5,2.5,1);disp(a);disp(b);disp(&b);}用基类类型的指针或引用做函数参数,实现多态性。用基类类型的指针或引用做函数参数,实现多态性。15注:在设置虚函数时应注意:1)只有类的成员函数才能声明为虚函数。2)静态成员函数不能声明为虚函数。3)内联函数不能是虚函数,即使虚函数在类的内部定义,编译时仍将其看做是非内联的。4)构造函数不能是虚函数。5)析构函数可以是虚函数。而且通常声明为虚函数。声明虚析构函数的目的在于:使用delete运算符删除一个对象时,能确保析构函数被正确地执行。这是因为,设置虚析构函数后,可以利用动态联编方式选择析构函数。(见下例(lt8_3a.cpp))16#includeiostreamusingnamespacestd;classA{public:~A(){cout调用A::~A()endl;}};classB:publicA{char*buf;public:B(inti){buf=newchar[i];};virtual~B(){delete[]buf;cout调用B::~B()endl;}};voidfun(A*pa){deletepa;}voidmain(){A*pa=newB(10);fun(pa);}virtual17在构造函数和析构函数中调用虚函数时采用静态联编,即所调用虚函数是自己类中或基类中定义的函数,而且优先调用自己类中的虚函数。三、构造函数和析构函数调用虚函数这是一种特例,在这种情况下,即在构造子类时调用父类的构造函数,而父类的构造函数中又调用了虚函数,这个虚函数即使被子类重写,也不允许发生多态的行为。即这时必须要调用父类的虚函数,而不调用子类重写后的虚函数。18例题:分析以下程序结果:#includeiostreamusingnamespacestd;classA{public:A(){fun();}voidfun(){cout基类A中的fun函数endl;}voidfunc(){fun();}};classB:publicA{public:B(){fun();}voidfun(){cout派生类B中的fun函数endl;}};voidmain(){Bb;b.func();}virtual20练习:分析以下程序结果(lt8_3.cpp)classA{public:A(){}virtualvoidfunc(){coutConstructingAendl;}~A(){}virtualvoidfund(){coutDestructorAendl;}};classB:publicA{public:B(){func();}voidfun(){coutComehereandgo..;func();}~B(){fund();}};classC:publicB{public:C(){}voidfunc(){coutClassCendl;}~C(){fund();}voidfund(){coutDestructorCendl;}};voidmain(){Cc;c.fun();}214356789101121总结:在构造函数和析构函数中调用虚函数时采用静态联编,所调用虚函数是自己类中或基类中定义的函数,且优先调用本类中的函数。C++中不支持构造函数定义为虚函数,析构函数可以定义为虚函数。只要基类的析构函数定义虚函数,则派生类的析构函数自动为虚函数(练习177页分析程序题1)22若虚函数定义时,不给出函数体,定义为如下形式:virtual函数类型函数名(参数)=0;则称为纯虚函数。四、纯虚函数与抽象类具有纯虚函数的类为抽象类,注意:1)抽象类只能作为基类来派生新类,不可定义对象,但是可以说明指向抽象类的指针或者引用。2)抽象类的派生类仍是抽象类。如果派生类中给出了基类所有纯虚函数的实现,则该派生类不再是抽象类。23若虚函数定义时,给出函数体为空,定义为如下形式:class类名{virtual函数类型函数名(参数){}}则称为
本文标题:c++程序设计第八章多态性和虚函数
链接地址:https://www.777doc.com/doc-3376734 .html