第4章继承性与多态性第4章继承性与多态性4.1继承与派生4.2派生中成员的标识与访问4.3运算符重载4.4虚函数习题第4章继承性与多态性4.1继承与派生4.1.1派生类的声明在C++中,派生类的一般声明语法为:class派生类名:[继承方式]基类名{派生类成员声明;};其中:(1)class:类声明的关键字,用于告诉编译器下面声明的是一个类。(2)派生类名:新生成的类名。第4章继承性与多态性(3)继承方式:规定了如何访问从基类继承的成员。继承方式关键字为private、public和protected,分别表示私有继承、公有继承和保护继承。如果不显式地给出继承方式关键字,系统的默认值就认为是私有继承(private)。类的继承方式指定了派生类成员以及类外对象对于从基类继承来的成员的访问权限,这将在后面详细介绍。(4)派生类成员:指除了从基类继承来的所有成员之外,新增加的数据和函数成员。第4章继承性与多态性4.1.2派生类生成过程classemployee{protected:char*name;//姓名intindividualEmpNo;//个人编号intgrade;//级别floataccumPay;//月薪总额staticintemployeeNo;//本公司职员编号目前最大值第4章继承性与多态性public:employee();~employee();voidpay();//计算月薪函数voidpromote(int);//升级函数voiddisplayStatus();//显示人员信息};第4章继承性与多态性classtechnician:publicemployee{private:floathourlyRate;//每小时酬金intworkHours;//当月工作时数public:technician();//构造函数voidpay();//计算月薪函数voiddisplayStatus();//显示人员信息};第4章继承性与多态性1.吸收基类成员2.改造基类成员3.添加新的成员4.1.3多继承1.多继承的声明第4章继承性与多态性在多继承中,各个基类名之间用逗号隔开,多继承的声明语法为:class派生类名:[继承方式]基类名1,[继承方式]基类名2,…,[继承方式]基类名n{派生类成员声明;};例如,声明一个名为MultiDerived的派生类,该类从基类Basel、Base2派生而来。第4章继承性与多态性classBase1{};classBase2{};classMultiDerived:publicBase1,privateBase2{public:};第4章继承性与多态性2.类族如图4-1所示为一个单继承的多层类族。A类B类D类C类E类图4-1单继承的多层类族示意图第4章继承性与多态性4.1.4类的继承方式表4-1列出了不同继承方式下基类成员各访问属性的变化情况。其中,第一行的访问属性是成员在基类中的访问属性,其他的访问属性表示基类成员在派生类中的访问属性。第4章继承性与多态性表4-1访问属性与继承的关系访问属性继承方式publicprotectedprivatepublicpublicprotectedprivateprotectedprotectedprotectedprivateprivateprivateprivateprivate第4章继承性与多态性这里所说的访问来自两个方面:一是派生类中的新增函数成员对从基类继承来的成员的访问;二是在派生类外部(非类族的成员),通过派生类的对象对从基类继承来的成员的访问。1.公有继承例4-1从vehicle(汽车)公有派生car(小汽车)类。程序代码如下:#includeiostream.hclassvehicle//基类vehicle类的声明{private://私有数据成员intwheels;protected://保护数据成员第4章继承性与多态性floatweight;public://公有函数成员vehicle(intin_wheels,floatin_weight){wheels=in_wheels;weight=in_weight;}intget_wheels(){returnwheels;}floatget_weight(){returnweight;}};第4章继承性与多态性classcar:publicvehicle//派生类car类的声明{private://新增私有数据成员intpassenger_load;public://新增公有函数成员car(intin_wheels,floatin_weight,intpeople=5):vehicle(in_wheels,in_weight)第4章继承性与多态性{passenger_load=people;}intget_passengers(){returnpassenger_load;}};voidmain(){carbluebird(4,1000);//声明car类的对象coutThemessageofbluebird(wheels,weight,passengers):endl;coutbluebird.get_wheels(),//输出小汽车的信息bluebird.get_weight(),bluebird.get_passengers()endl;}第4章继承性与多态性通过此例题,我们可以比较直观地看到,一个基类以公有方式产生了派生类之后,派生类的成员函数以及派生类的对象是如何访问从基类继承的公有成员的。程序运行结果为:Themessageofbluebird(wheels,weight,passengers):4,1000,5第4章继承性与多态性2.保护继承采用保护继承方式重做例4-1,这时基类vehicle的定义和主函数main()保持不变,派生类car的声明修改如下:classcar:protectedvehicle{private:intpassenger_load;public:car(intin_wheels,floatin_weight,intpeople=5):vehicle(in_wheels,in_weight)第4章继承性与多态性{passenger_load=people;}intget_wheels(){returnvehicle::get_wheels();}//重新定义get_wheels()floatget_weight(){returnweight;}//重新定义get_weight()intget_passengers(){returnpassenger_load;}};第4章继承性与多态性3.私有继承可以归纳为以下四种:(1)不可访问的成员。(2)私有成员。(3)保护成员。(4)公有成员。第4章继承性与多态性4.1.5派生类的构造函数和析构函数1.构造函数派生类构造函数声明的一般语法形式为:派生类名::派生类名(参数总表):基类名1(参数表1),…,基类名n(参数表n),内嵌对象名1(内嵌对象参数表1),…,内嵌对象名m(内嵌对象参数表m){派生类新增成员的初始化语句;}第4章继承性与多态性其中:(1)派生类的构造函数名与派生类名相同。(2)参数总表需要列出初始化基类数据、新增内嵌对象数据及新增一般成员数据所需要的全部参数。(3)冒号之后,列出需要使用参数进行初始化的基类名和内嵌成员名及各自的参数表,各项之间用逗号分隔。第4章继承性与多态性2.析构函数例4-2有三个基类Base1、Base2和Base3,它们都有自己的构造函数和析构函数,其中Base3有一个默认的构造函数,即不带参数的构造函数,其余两个的构造函数都带有参数。类Derive由这三个基类经过公有派生而来。派生类新增加了三个私有对象成员memberBase1、memberBase2和memberBase3,它们分别是Base1、Base2和Base3类的对象。另外,派生类定义了自己的构造函数,而没有定义析构函数,即采用默认的析构函数。程序代码如下:第4章继承性与多态性#includeiostream.hclassBase1//基类Base1,构造函数有参数{public:Base1(inti){coutconstructingBase1iendl;}~Base1(){coutdestructingBase1endl;}//Base1的析构函数};第4章继承性与多态性classBase2//基类Base2,构造函数有参数{public:Base2(intj){coutconstructingBase2jendl;}~Base2(){coutdestructingBase2endl;}//Base2的析构函数};classBase3//基类Base3,构造函数无参数第4章继承性与多态性{public:Base3(){coutconstructingBase3endl;}~Base3(){coutdestructingBase3endl;}//Base3的析构函数};classDerive:publicBase2,publicBase1,publicBase3//派生新类第4章继承性与多态性{private://派生类新增私有对象成员Base1memberBase1;Base2memberBase2;Base3memberBase3;public://派生类的构造函数Derive(inta,intb,intc,intd):Base1(a),memberBase2(d),memberBase1(c),Base2(b){}};voidmain(){Deriveobject(2,4,6,8);}第4章继承性与多态性程序运行的结果完全证实了这种分析,程序运行结果为:constructingBase24constructingBase12constructingBase3constructingBase16constructingBase28constructingBase3destructingBase3destructingBase2destructingBase1destructingBase3destructingBase1destructingBase2第4章继承性与多态性4.2派生中成员的标识与访问4.2.1作用域分辨1.作用域分辨符作用域分辨符就是我们经常见到的“::”,它可以用来限定要访问的成员归属哪个类,一般的使用形式为:类名::成员名类名::成员名(参数表)第4章继承性与多态性2.多继承中作用域分辨符的使用例4-3有一个基类Level1,声明了成员数据n1和成员函数fun1(),由Level1公有派生Level21和Level22两个类,再以Level21和Level22作为基类共同公有派生产生了新类Level3,它们的派生关系及派生类的结构如图4-2所示。第4章继承性与多态性Level21类intn21;Level3类intn3;voidfun3();Level3类intLevel21::n1;voidLevel21::fun1();Level1类intn1;voidfun1();(b)(a)Level22类intn22;intLevel22::n1;intLevel21::n21;intLevel21::n22;intn3;voidLevel22::fun1();voidfun3();图4-2多继承情况下派生类Level3继承关系、成员构成图(a)继承关系;(b) Level3类结构第4章继承性与多态性现在我们来讨论同名成员n1和fun1()的标识与访问问题。间接基类Level1的成员经过两次派生之后,通过不同的派生路径以相同的名字出现在派生类Level3中。这时,如果使用基类名Level1来限定,同样无法表明成员到底是从Lev