第七章继承性和派生类_第1页
第七章继承性和派生类_第2页
第七章继承性和派生类_第3页
第七章继承性和派生类_第4页
第七章继承性和派生类_第5页
已阅读5页,还剩108页未读 继续免费阅读

下载本文档

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

文档简介

第七章继承性和派生类7.1基类和派生类

7.2单继承

7.3多继承

7.4虚基类

编辑课件7.1基类和派生类继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能。这样产生新的类,称派生类。派生类不是简单地继承基础类的特性,它可以调整部分成员的特性,也可以增加一些新成员。继承呈现了面向对象程序设计的层次结构。体现了由简单到复杂的认识过程。多态性(polymorphism)也是面向对象程序设计的标志性特征。多态性是考虑在不同层次的类中,以及在同一类中,同名的成员函数之间的关系问题。函数的重载,运算符的重载,属于多态性中的编译时的多态性。本章讲解的以虚基类为基础的多态性是运行时的多态性。体现了类推和比喻的思想方法。

编辑课件生物类动物类植物类微生物类脊椎动物类其它动物类哺乳动物类其它脊椎动物类灵长动物类其它动物类人类狒狒类其它灵长动物类编辑课件7.1基类和派生类1、基类与派生类基类(父类):已存在的用来派生新类的类;派生类(子类):由已存在的类派生出的新类;2、单继承与多继承单继承:从一个基类派生的继承;多继承:从多个基类派生的继承;编辑课件7.1基类和派生类基类1基类2……基类n派生类1派生类2基类派生类1派生类2(a)多重继承

(b)单继承

一个基类可以直接派生出多个派生类

派生出来的新类同样可以作为基类再继续派生出更新的类,依此类推形成一个层次结构。编辑课件7.1.1派生类的定义单继承的定义格式为:class派生类名:继承方式基类名 { 派生类新定义成员 };public:公有派生private:私有派生protected:保护派生规定基类成员在派生类中的访问权限多继承的定义格式为:class派生类名:继承方式1基类名1,

继承方式2基类名2,… { 派生类新定义成员};编辑课件单继承的定义格式:classB//定义基类B{private: intx;protected: inty;public: intz; ...};classA:publicB

//由类B派生出类A{private: inta;protected: intb;public: intc; ...}Aa;//定义类A的一个对象a编辑课件7.1.1派生类的定义编制派生类时可分四步

吸收基类的成员

改造基类成员

发展新成员

重写构造函数与析构函数

不论是数据成员,还是函数成员,除构造函数与析构函数外全盘接收

声明一个和某基类成员同名的新成员派生类中的新成员就屏蔽了基类同名成员称为同名覆盖派生类新成员必须与基类成员不同名,它的加入保证派生类在功能上有所发展。编辑课件7.1.2派生类的三种继承方式:公有继承(public)保护继承(private)私有继承(protected)编辑课件公有继承:公有继承其特点是:

基类的公有成员和保护成员作为派生类的成员时,都保持原有状态,而私有成员仍是私有。编辑课件公有继承:特别提示公有继承时,派生类的对象只可访问基类中的公有成员,不能访问其它成员。派生类的成员函数可以访问基类中的公有成员和保护成员,不可访问其私有成员。编辑课件公有继承:Public派生类对象基类对象Public编辑课件classB{private: intx;protected: inty;public: intz; ...};classA:publicB

{private: inta;protected: intb;public: intc; ...}Aa;说明:类B是基类,类A是从类B公有派生的,因此类B中的public、protected属性的成员可继承到类A中来,且保持原来的属性。因此,类A中有5个数据成员:a,b,c,y(protected属性),z(public属性)。对象a可以直接访问public成员z和c,不能访问a,b,y。编辑课件注意:在不考虑派生类时,类中的private和protected属性的成员没有什么不同,它们都可以被类的成员函数访问,而都不能被该类的对象直接访问。其差异主要是在派生类中,当公有继承时,基类中protected属性的成员可以作为派生类的protected属性的成员,而private属性的成员不能作为派生类的成员编辑课件classstudent{private:intage;protected:charsex;public:intGetage();};classgraduatestudent:publicstudent{private:intstunum;public:intGetnum();};voidgraduatestudent::Getnum()//派生类成员函数定义{

//cout<<”age:”<<age<<endl;//不可访问基类的私有成员cout<<”stunum:”<<stunum<<endl;//派生类的私有成员cout<<”age:”<<Getage()<<endl;//基类的公有成员cout<<“sex:”<<sex<<endl;

//即:student::sex

基类的保护成员}编辑课件保护继承:其特点是:基类的所有公有成员和保护成员都作为派生类的保护成员,基类的私有成员仍是私有的。即基类的公有成员和保护成员都作为派生类的保护成员。派生类的其他成员可以直接访问它们。派生类的对象不可以直接访问它们。编辑课件.编辑课件classB{private: intx;protected: inty;public: intz; ...};classA:protectedB

{private: inta;protected: intb;public: intc; ...}Aa;说明:类B是基类,类A是从类B保护派生的,因此类B中的public、protected属性的成员可继承到类A中来,均变为protected属性。因此,类A中有5个数据成员:a,b,c,y(protected属性),z(protected属性)。对象a可以直接访问public成员c,不能访问a,b,y,z。编辑课件私有继承:基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。特别提示编辑课件.编辑课件classB{private: intx;protected: inty;public: intz; ...};classA:privateB

{private: inta;protected: intb;public: intc; ...}Aa;说明:类B是基类,类A是从类B私有派生的,因此类B中的public、protected属性的成员可继承到类A中来,均变为private属性。因此,类A中有5个数据成员:a,b,c,y(private属性),z(private属性)。对象a可以直接访问public成员c,不能访问a,b,y,z。编辑课件公有派生和私有派生的访问权限不可直接访问不可直接访问private不可直接访问privateprotected不可直接访问privatepublic私有派生

不可直接访问不可直接访问private不可直接访问protectedprotected可直接访问publicpublic公有派生

在派生类对象外访问派生类对象的基类成员在派生类中对基类成员的访问限定基类中的访问限定

派生方式

编辑课件#include<iostream.h>classA{public:voidf1();protected:intj1;private:inti1;};classB:publicA{public:voidf2();protected:intj2;private:inti2;};classC:publicB{public:voidf3();};1、派生类B中成员函数f2()能否访问基类A中的成员:f1()、j1和i1?2、派生类B的对象b1能否访问基类A中的成员:f1()、j1和i1?3、派生类C中的成员函数f3()能否访问直接基类B中的成员:f2()、j2和i2?能否访问间接基类A中的成员:f1()、j1和i1?4、派生类C的对象c1能否访问直接基类B中的成员:f2()、j2和i2?能否访问间接基类A中的成员:f1()、j1和i1?编辑课件1、派生类B中成员函数f2()能否访问基类A中的成员:f1()、j1和i1?

可以访问f1()和j1,不可以访问i1;原因:类B对类A是直接继承,可以访问A中的公有成员和保护成员,而不可以访问私有成员;2、派生类B的对象b1能否访问基类A中的成员:f1()、j1和i1?

可以访问f1(),不可以访问j1和i1;原因:类B的对象b1对类A中的成员是水平访问,可以访问A中的公有成员,而不可以访问保护成员和私有成员;编辑课件4、派生类C的对象c1能否访问直接基类B中的成员:f2()、j2和i2?能否访问间接基类A中的成员:f1()、j1和i1?

可以访问直接基类中的f2()和j2以及间接基类中的f1()和j1,不可以访问i2和i1;

原因:类C对类B是直接继承,原因同1;类C对类A是垂直访问,可以访问A中的公有成员和保护成员,而不可以访问私有成员;可以访问直接基类中的f2()以及间接基类中的f1(),其他都不可以访问;

原因:类C的对象c1对B中的成员是水平访问,原因同2;c1对A的访问,相当于先直接继承后水平访问;3、派生类C中的成员函数f3()能否访问直接基类B中的成员:f2()、j2和i2?能否访问间接基类A中的成员:f1()、j1和i1?编辑课件#include<iostream.h>classA{public:voidf(inti){cout<<i<<endl;}voidg(){cout<<"g"<<endl;}};classB:A{public:voidh(){cout<<"h"<<endl;}A::f;};voidmain(){Bd1;d1.f(6);

d1.g();d1.h();}缺省继承方式为private将基类中的成员说明为派生类中的成员编译错。B以私有继承方式继承A,因此B的对象b1不能访问A的成员函数输出(2):6h输出(5):6gh编辑课件问题:1、执行该程序时,哪个语句会出现编译错?2、去掉出错语句后,执行结果是什么?3、类B从类A继承时的缺省继承方式是什么?4、派生类B中,A::f的含义是什么?5、将B的继承方式改为public,输出结果是什么?编辑课件7.2单继承在单继承中,每个类可以生成多个派生类,但是每个派生类只能有一个基类。派生类中只有一个基类是单继承的主要特点。编辑课件7.2.1派生类构造函数和析构函数1.派生类的构造函数构造函数不能被继承;派生类构造函数的工作:对自己的数据成员进行初始化;负责调用基类构造函数使基类的数据成员得以初始化;调用子对象的构造函数,对派生类中的子对象进行初始化;必须在成员初始化列表中进行编辑课件派生类构造函数格式:

<派生类名>(<派生类构造函数总参数表>)

:<基类构造函数>(<参数表1>),

<子对象名>(<参数表2>)

{<派生类中数据成员初始化>}成员初始化列表编辑课件成员初始化列表B(inti,intj,intk):a(i,j){b=k;}子对象a对子对象成员函数的调用输出:6,78编辑课件#include<iostream.h>classA{public: A(inti); voidprint(); constint&r;//常引用类型private:

constinta;

//常类型

staticconstintb;

};

//静态常类型constintA::b=10;

//常静态成员的赋初值A::A(inti):a(i),r(a)

//对常数据成员的构造{}voidA::print(){cout<<a<<":"<<b<<":"<<r<<endl;}voidmain(){ Aa1(100),a2(0); a1.print(); a2.print();}A::A(inti){a=i,r=a;}//不能这样哟!结果为:100:10:1000:10:0编辑课件派生类构造函数的调用顺序如下:基类的构造函数子对象类的构造函数(若有)派生类构造函数编辑课件注意:1、若基类中未定义构造函数,则派生类构造函数的定义中可以省略对基类构造函数的调用。2、若基类的构造函数使用了参数,则派生类必须定义构造函数,为基类构造函数提供参数。编辑课件#include<iostream.h>classA{public:A(){a=0;cout<<"A'sdefaultconstructorcalled.\n";}A(inti){a=i;cout<<"A'sconstructorcalled.\n";}~A(){cout<<"A'sdestructorcalled.\n";}voidprint()const{cout<<a<<",";}intGeta(){returna;}private:inta;};classB:publicA{public:B(){b=0;cout<<"B'sdefaultconstructorcalled.\n";}B(inti,intj,intk);~B(){cout<<"B'sdestructorcalled.\n";}voidprint();private:intb;Aaa;};B::B(inti,intj,intk):A(i),aa(j){b=k;cout<<"B'sconstructorcalled.\n";}voidB::print(){A::print();cout<<b<<","<<aa.Geta()<<endl;}voidmain(){Bbb[2];bb[0]=B(1,2,5);bb[1]=B(3,4,7);for(inti=0;i<2;i++) bb[i].print();}编辑课件#include<iostream.h>classdata{ intx;public: data(intx){data::x=x;cout<<"classdata\n";}};classA{public:A(intx):d1(x){cout<<"classA\n";}private: datad1;};classB:publicA{datad2;public:B(intx):A(x),d2(x){cout<<"classB\n";}};classC:publicB{public:C(intx):B(x) {cout<<"classC\n";}};voidmain(){Cobject(5);}classdataclassAclassdataclassBclassC编辑课件派生类析构函数:执行派生类的析构函数时,基类的析构函数也将被调用;析构函数不能被继承;析构函数的执行顺序与构造函数严格相反;派生类的析构函数;基类的析构函数;编辑课件#include<iostream.h>classM{public:M(){m1=m2=0;};M(inti,intj);~M();voidPrint();private:intm1,m2;};M::M(inti,intj){m1=i,m2=j;cout<<"M'sconstructorcalled."<<m1<<","<<m2<<endl;}M::~M(){cout<<"M'sdestructorcalled."<<m1<<","<<m2<<endl;}voidM::Print(){cout<<m1<<","<<m2<<",";}classN:publicM{public:N(){n=0;}N(inti,intj,intk);~N();voidPrint();private:intn;};N::N(inti,intj,intk):M(i,j),n(k){cout<<"N'scostructorcalled."<<n<<endl;}N::~N(){cout<<"N'sdestructorcalled."<<n<<endl;}voidN::Print(){M::Print();cout<<n<<endl;}voidmain(){Nn1(5,6,7),n2(-2,-3,-4);n1.Print();n2.Print();}编辑课件运行结果:编辑课件3.派生类构造函数使用中应注意的问题派生类构造函数的定义中可以省略对基类构造函数的调用,其条件是在基类中必须有缺省的构造函数或者根本没有定义任何构造函数;当基类的构造函数使用一个或多个参数时,派生类必须定义构造函数,提供将参数传递给基类构造函数的途径;编译器自动生成缺省构造函数设基类数据成员为m个,派生类数据成员为n个,派生类的参数个数为x,则:0=<x<=m+n;编辑课件#include<iostream.h>classA{public:A(){a=0;}A(inti){a=i;}voidPrint(){cout<<a<<",";}private:inta;};classB:publicA{public:B(){b1=b2=0;}B(inti){b1=i;b2=0;}B(inti,intj,intk):A(i),b1(j),b2(k){}voidPrint(){A::Print();cout<<b1<<","<<b2<<endl;}private:intb1,b2;};voidmain(){Bd1,d2(5),d3(4,5,6);d1.Print();d2.Print();d3.Print();}输出:0,0,00,5,04,5,6编辑课件7.2.2子类型和赋值兼容规则1、子类型有一个特定的类型S,当且仅当它至少提供了类型T的行为,则称类型S是类型T的子类型。子类型是类型间的一般和特殊的关系。在继承中,公有继承可以实现子类型。如:classA{public:voidprint()const{cout<<“ok!”;}};classB:publicA{public:voidf(){cout<<“No!”;}};voidf1(constA&r){r.print();}voidmain(){Bb;f1(b);}结果为:ok!对类A的对象操作的函数,也就可对类A的子类(类B)的对象进行操作编辑课件2.类型适应指两种类型之间的关系。如:派生类适应于基类。即派生类的对象可以用于基类对象所能使用的场合。子类型化与类型适应是一致的。子类型的重要性是能减轻编程负担。一个函数可以用于某类型的对象,也就可用于该类型的各个子类型的对象,不必进行函数重载。编辑课件3.赋值兼容规则赋值兼容规则是指在需要基类对象的任何地方都可以使用公有派生类的对象来替代。在替代之后,派生类对象就可以作为基类的对象使用,但只能使用从基类继承的成员。赋值兼容规则替代的几种情况:派生类的对象可以赋值给基类对象。派生类的对象可以初始化基类的引用。派生类的对象的地址可以赋给指向基类的指针。编辑课件例题1下列对派生类的描述,()是错的。A.一个派生类可以作另一个派生类的基类。B.派生类至少有一个基类。C.派生类的成员除了它自己的成员外,还包含了它的基类的成员。D.派生类中继承的基类成员的访问权限到派生类保持不变。答案:D编辑课件例题2派生类的对象对它基类成员中()是可以访问的。A.公有继承的公有成员;B.公有继承的私有成员;C.公有继承的保护成员;D.私有继承的公有成员。答案:A编辑课件例题3对基类和派生类的关系描述中,()是错误。A.派生类是基类的具体化;B.派生类是基类的子集;C.派生类是基类定义的延续;D.派生类是基类的组合。答案:B编辑课件例题4派生类的构造函数的成员初始化列表中,不能包含()。A.基类的构造函数;B.派生类中子对象的初始化;C.基类的子对象的初始化;D.派生类中一般数据成员的初始化。答案:C编辑课件7.3多继承在册人员学生(单继承)教职工(单继承)兼职教师(单继承)教师(单继承)行政人员(单继承)工人(单继承)研究生(单继承)行政人员兼教师(多重继承)在职研究生(多重继承)研究生助教(多重继承)编辑课件7.3多继承多继承的定义格式为:class派生类名:继承方式1基类名1,

继承方式2基类名2,… { 派生类新定义成员};

由多个基类共同派生出新的派生类,这样的继承结构被称为多重继承或多继承(multiple-inheritance)

编辑课件多重继承的定义格式:如:classA{…};classB{…};classC:publicA,publicB{…};根据继承的规定,派生类C的成员包含了基类A中成员和基类B中成员及该类本身的成员。编辑课件#include<iostream.h>classA{public: voidprintA(){cout<<"Hello";}};classB{public: voidprintB(){cout<<"C++";}};classC:publicA,publicB{public: voidprintC(){cout<<"World!\n";}};voidmain(){Cobj;; obj.printA(); obj.printB(); obj.printC();}HelloC++World!编辑课件7.3.2多继承的构造函数和析构函数

<派生类名>(<总参数表>):<基类名1>(<参数表1>),<基类名2>(<参数表2>)……<子对象名>(<参数表n+1>),…...{<派生类构造函数体>}它必须同时负责该派生类所有基类构造函数的调用。同时,派生类的参数个数必须包含完成所有基类初始化所需的参数个数。编辑课件多继承的构造函数:派生类构造函数的调用顺序是:先执行所有基类的构造函数再执行子对象类的构造函数(若有)再执行派生类本身的构造函数注意:

同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的各基类顺序,与派生类构造函数中所定义的成员初始化表的各项顺序无关。编辑课件

定义基类B1

定义基类B2

定义基类B3派生类构造函数

定义派生类A

定义子对象bb

调用不同基类中的同名函数编辑课件运行结果:编辑课件多继承的析构函数:

在多继承中,析构函数的执行顺序与构造函数的顺序正好相反。编辑课件#include<iostream.h>classA{public: A(){cout<<"AConstructor"<<endl;} ~A(){cout<<"ADestructor"<<endl;}};classB{public: B(){cout<<"BConstructor"<<endl;} ~B(){cout<<"BDestructor"<<endl;}};classC:publicA,publicB{public: C(){cout<<"CConstructor"<<endl;} ~C(){cout<<"CDestructor"<<endl;}};voidmain(){Cc;}AConstructorBConstructorCConstructorCDestructorBDestructorADestructor编辑课件7.3.3多继承的二义性问题1、产生二义性的原因在多继承情况下,造成的对基类中某个成员的访问出现的不唯一的情况;编辑课件二义性问题classAclassC:publicA,publicB{{public:public:

voidf();voidg();};voidh();classB};{public:

voidf();

voidg();};voidf();c1.f()A.f()B.f()C编辑课件二义性问题问题:若定义Cc1;,则c1.f()是否正确?答:c1.f()将产生二义性;原因:不能识别是调用类A或类B的f函数;解决方法:

a.区别出是类A或类B的f函数;

c1.A::f();

或c1.B::f();

b.在类中定义同名函数f;编辑课件二义性问题当一个派生类从多个基类派生,而这些基类又有一个共同的基类,则对该基类中说明的成员进行访问时,可能会出现二义性;编辑课件二义性问题classAclassB2:publicA{{public:private:inta;intb2;};};classB1:publicAclassC:publicB1,publicB2{{private:public:intb1;intf();};private:intc;};c1.aA.aB1.b1CB2.b2A.a编辑课件二义性问题问题:若定义Cc1;,则c1.a与c1.A::a是否正确?答:c1.a与c1.A::a将产生二义性;原因:不能识别是通过类B1或类B2调用类A的a;解决方法:

a.区别出是通过类B1或类B2调用类A的a;

c1.B1::a;

或c1.B2::a;

b.虚基类;编辑课件2、二义性解决方法利用成员名限定法消除二义性;在类中定义一个同名成员;虚基类;编辑课件3、支配规则(定义同名成员方法)支配规则:类X中的名字N支配类Y中同名的名字N是指类X以类Y为它的一个基类;如果一个名字支配另外一个名字,则二者之间不存在二义性。当选择该名字时,使用支配者的名字;编辑课件4、说明一个类不能从同一个类中直接继承一次以上;二义性检查在访问控制和类型检查之前进行,访问控制和类型检查不能解决二义性问题;编辑课件编辑课件运行结果:编辑课件7.4虚基类

引入目的:解决二义性问题;格式:virtual<继承方式><基类名>说明:关键字virtual与关键字public或private的相对位置无关,但必须位于虚基类名之前,且virtual只对紧随其后的基类名起作用;编辑课件7.4虚基类例如:classD:virtualpublicA,privateB,virutalpublicC其中:类A和类C是虚基类,而类B是非虚基类编辑课件classA{public:voidf();protected:inta;};classB:virtualpublicA{protected:intb;};classC:virtualpublicA{protected:intc;};classD:publicB,publicC{public:intg();private:intd;};虚基类虚基类BD.g()CA.f()下列各语句是否正确?Dn;n.f();voidD::g(){f();}正确能够唯一确定调用类A的f();编辑课件7.4虚基类AAB1B2C非虚基类的类层次AB1B2C虚基类的类层次编辑课件虚基类的初始化由于派生类的对象中只有一个虚基类子对象。为保证虚基类子对象只被初始化一次,这个虚基类构造函数必须只被调用一次。编辑课件虚基类的初始化C++规定:虚基类子对象是由最派生类的构造函数通过调用虚基类的构造函数进行初始化的。虚基类的构造函数在非虚基类之前调用;若同一层次中包含多个虚基类,这些虚基类的构造函数按它们说明的次序调用;若虚基类由非虚基类派生而来,则仍先调用基类构造函数,再调用派生类的构造函数。编辑课件最派生类:BDCAE若定义Ee;则E是最派生类;若定义Dd;则D是最派生类;若定义Bb;则B是最派生类;若定义Cc;则C是最派生类;编辑课件#include<iostream.h>classbase1{public:base1(){cout<<"classbase1"<<endl;}};classbase2{public:base2(){cout<<"classbase2"<<endl;}};classlevel1:publicbase2,virtualpublicbase1{public:level1(){cout<<"classlevel1"<<endl;}};classlevel2:publicbase2,virtualpublicbase1{public:level2(){cout<<"classlevel2"<<endl;}};classtoplevel:publiclevel1,virtualpubliclevel2{public:toplevel(){cout<<"classtoplevel1"<<endl;}};voidmain(){toplevelobj;}编辑课件运行结果:编辑课件说明:虚基类子对象由最派生类构造函数进行初始化;虚基类子对象只被初始化一次;虚基类构造函数先于非虚基类构造函数执行;编辑课件基类子对象数据成员初始化虚基类非虚基类常数据成员静态数据成员一般数据成员存在多个基类时,执行顺序取决于派生类定义时的顺序存在多个子对象时,执行顺序取决于类中声明的顺序成员初始化列表类外初始化编辑课件设置虚基类的目的是:A简化程序;B消除二义性;C提高运行效率D减少目标代码答案:B编辑课件带有虚基类的多层派生类构造函数的成员初始化列表中都要列出虚基类的构造函数,这样将对虚基类的子对象初始化()A与虚基类下面的派生类个数有关B多次C二次D一次答案:D编辑课件#include<iostream.h>classA{public:A(inti,intj){a=i;b=j;}voidMove(intx,inty){a+=x;b+=y;}voidShow(){cout<<"("<<a<<","<<b<<")"<<endl;}private:inta,b;};classB:publicA{public:B(inti,intj,intk,intl):A(i,j),x(k),y(l){}voidShow(){cout<<x<<","<<y<<endl;}voidfun(){Move(3,5);}voidf1(){A::Show();}private:intx,y;};voidmain(){Ae(1,2);e.Show();Bd(3,4,5,6);d.fun();d.A::Show();d.B::Show();d.f1();}编辑课件运行结果:编辑课件#include<iostream.h>classP{public:P(intp1,intp2){pri1=p1;pri2=p2;}intinc1(){return++pri1;}intinc2(){return++pri2;}voiddisplay(){cout<<"pri1="<<pri1<<",pri2="<<pri2<<endl;}private:intpri1,pri2;};classD1:virtualprivateP{public:D1(intp1,intp2,intp3):P(p1,p2){pri3=p3;}intinc1(){returnP::inc1();}intinc3(){return++pri3;}voiddisplay(){P::display();cout<<"pri3="<<pri3<<endl;}private:intpri3;};编辑课件classD2:virtualpublicP{public:D2(intp1,intp2,intp4):P(p1,p2){pri4=p4;}intinc1(){ P::inc1(); P::inc2(); returnP::inc1();}intinc4(){return++pri4;}voiddisplay(){P::display();cout<<"pri4="<<pri4<<endl;}private:intpri4;};编辑课件classD12:privateD1,publicD2{public:D12(intp11,intp12,intp13,intp21,intp22,intp23,intp):D1(p11,p12,p13),D2(p21,p22,p23),P(p11,p21){pri12=p;}intinc1(){D2::inc1();returnD2::inc1();}intinc5(){return++pri12;}voiddisplay(){cout<<"D2::display()\n";D2::display();cout<<"pri12="<<pri12<<endl;}private:intpri12;};编辑课件voidmain(){D12d(1,2,3,4,5,6,7);d.display();cout<<endl;d.inc4();d.inc5();d.D12::inc1();d.display();}编辑课件运行结果:编辑课件8.7多态性与虚函数C++的三大特征:封装性继承性多态性编辑课件

多态性是指同一个消息被不同类型的对象接收时产生不同的行为,特点就是一个接口,多个实现。C++中多态性按照类型可以分为强制多态、过载多态、包含多态和参数多态四种。8.7多态性与虚函数编辑课件8.7多态性与虚函数强制多态是指通过语义操作,强制数据做本不属于该类型数据的操作。编译器内部的数据的隐式转换,比如3.0+4操作时转换成3.0+4.0就属于此种类型重载多态是指函数重载,同名的操作在不同的环境下有不同的行为。前面学习过的普通函数重载和将要学习的类成员函数重载、运算符重载都属于此种类型。包含多态是指在同一类族中定义于不同类中的同名函数的多态行为。我们本章将要学习的虚函数就属于此种类型。参数多态是指功能、结构实现相同但所作用于的数据类型不同,也就是数据类型参数化的多态。函数模板和类模板就属于此种多态。编辑课件多态的实现:多态是指同一个消息被不同的对象接收产生不同的行为,因此,多态在实现的时候必须确定消息的操作对象。我们根据消息和对象相结合的时间分为两种:在程序编译连接阶段完成的,也就是说在编译的过程中确定了消息的操作对象,我们称为静态联编(静态束定)。在程序运行阶段完成的,也就是说在程序运行的过程中才确定消息的操作对象,我们称为动态联编(动态束定)。编辑课件多态的实现:多态性简单多态性重要多态性虚函数函数重载、运算符重载

静态联编动态联编编辑课件#include<iostream.h>classPoint{public: Point(doublei,doublej){x=i;y=j;} double

Area()const{return0.0;}private: doublex,y;};classRectangle:publicPoint{public: Rectangle(doublei,doublej,doublek,doublel); doubleArea()const{returnw*h;}private: doublew,h;};Rectangle::Rectangle(doublei,doublej,doublek,doublel):Point(i,j){ w=k;h=l;}voidfun(Point&s){ cout<<"Area="<<s.Area()<<endl;}voidmain(){

Rectanglerec(3.0,5.2,15.0,25.0); fun(rec);}Area=0编辑课件动态联编:动态联编:在程序执行时进行的束定;实现:C++动态束定在虚函数的支持下实现;动态联编的原因:当实现一个子类型时变动了其基类中相应行为的实现时,必须将这种变动告诉编译器,即进行动态联编;编辑课件8.7.1虚函数的定义1、虚函数虚函数是动态联编的基础;虚函数是非static成员函数;virtual<类型说明符><函数名>(<参数表>)说明方法:编辑课件1、虚函数含义:若类中一成员函数被说明为虚函数,则该成员函数在派生类中可能有不同的实现。当使用该成员函数操作指针或引用所标识的对象时,对该成员函数调用可采用动态联编方式。操作方法:

动态联编只能通过指针或引用标识对象来操作虚函数。如果采用一般类型的标识对象来操作虚函数,则将采用静态联编方式调用虚函数。编辑课件#include<iostream.h>classPoint{public:Point(doublei,doublej){x=i;y=j;}

virtualdoubleArea()const{return0;}private:doublex,y;};classRectangle:publicPoint{public:Rectangle(inti,intj,intk,intl);

virtualdoubleArea()const{returnw*h;}private:doublew,h;};Rectangle::Rectangle(inti,intj,intk,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>classPoint{public:Point(doublei,doublej){x=i;y=j;}virtualdoubleArea()const{return0;}private:doublex,y;};classRectangle:publicPoint{public:Rectangle(inti,intj,intk,intl);virtualdoubleArea()const{returnw*h;}private:doublew,h;};Rectangle::Rectangle(inti,intj,intk,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>classPoint{public:Point(doublei,doublej){x=i;y=j;}virtualdoubleArea()const{return0;}private:doublex,y;};classRectangle:publicPoint{public:Rectangle(inti,intj,intk,intl);virtualdoubleArea()const{returnw*h;}private:doublew,h;};Rectangle::Rectangle(inti,intj,intk,intl):Point(i,j){w=k;h=l;}voidfun(Points){cout<<s.Area()<<endl;}voidmain(){Rectanglerect(3.0,5.2,15.0,25.0);fun(rect);}输出:0编辑

温馨提示

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

评论

0/150

提交评论