C语言继承与派生.ppt

上传人:牧羊曲112 文档编号:6504303 上传时间:2023-11-07 格式:PPT 页数:99 大小:500KB
返回 下载 相关 举报
C语言继承与派生.ppt_第1页
第1页 / 共99页
C语言继承与派生.ppt_第2页
第2页 / 共99页
C语言继承与派生.ppt_第3页
第3页 / 共99页
C语言继承与派生.ppt_第4页
第4页 / 共99页
C语言继承与派生.ppt_第5页
第5页 / 共99页
点击查看更多>>
资源描述

《C语言继承与派生.ppt》由会员分享,可在线阅读,更多相关《C语言继承与派生.ppt(99页珍藏版)》请在三一办公上搜索。

1、第7章 继承与派生,7.1 继承与派生 7.2 多继承 7.3 类的继承方式 7.4 派生类的构造和析构函数 7.5 派生中成员的标识与访问 7.6 虚基类 7.7 类模板的派生和继承,7.1 继承与派生,7.1.1 继承与派生的概念 举个简单的例子:“狗”和“黑狗”。当谈论“狗”的时候,知道它是哺乳动物,有4条腿,1条尾巴,喜欢啃肉骨头,。现在谈论“黑狗”,人们会怎么说呢?当然可以说:“黑狗是一种哺乳动物,有4条腿,1条尾巴,喜欢吃肉骨头,并且它的毛是黑色的”。但是人们一般都不这么说,而是说:“黑狗就是黑毛的狗”。比较一下这两种说法,显然后一种说法更好。那么它好在哪里呢?第一,它更简炼;第二

2、,更重要的是它反映了“狗”和“黑狗”这两个概念的内在联系。“狗”和“黑狗”之间存在一条重要的联系,那就是所有的“黑狗”都是“狗”,或者说,“黑狗”是一类特殊的“狗”。根据这一条,“狗”所具有的特征,例如4条腿,1条尾巴等,“黑狗”自然都具有。也就是说,“黑狗”从“狗”那里继承了“狗”的全部特征。,所谓继承,就是新的类从已有类那里得到已有的特性。从另一个角度来看,从已有类产生新类的过程就是类的派生。已有的类称为基类或父类,产生的新类称为派生类或子类。派生类同样也可以作为基类再派生新的类,这样就形成了类的层次结构。类的继承和派生的层次结构,可以说是人们对自然界中的事物进行分类、分析和认识的过程在程

3、序设计中的体现。现实世界中的事物都是相互联系、相互作用的,人们在认识过程中,根据事物的实际特征,抓住其共同特性和细小差别,利用分类的方法进行分析和描述。C+中有两种继承:单一继承和多重继承。对于单一继承,派生类只能有一个基类;对于多重继承,派生类可以有多个基类。,图7-1 交通工具分类层次图,例如,对于交通工具的分类见图7-1。,7.1.2 单一继承的派生类声明 在C+中,派生类的一般声明语法如下:class:继承方式 派生类成员声明;其中:class是类声明的关键字,用于告诉编译器下面声明的是一个类。派生类名是新生成的类名。,继承方式规定了如何访问从基类继承的成员。继承方式关键字为priva

4、te、public和protected,分别表示私有继承、公有继承和保护继承。如果不显式地给出继承方式关键字,系统的默认值就认为是私有继承(private)。类的继承方式指定了派生类成员以及类外对象对于从基类继承来的成员的访问权限,这将在7.3节中详细介绍。派生类成员指除了从基类继承来的所有成员之外,新增加的数据和函数成员。这些新增的成员正是派生类不同于基类的关键所在,是派生类对基类的发展。当重用和扩充已有的代码时,就是通过在派生类中新增成员来添加新的属性和功能。可以说,这就是类在继承基础上的进化和发展。,例如,从基类vehicle(汽车)公有派生car(小汽车)类的声明形式如下:class

5、vehicle/基类vehicle类的声明 private:/私有数据成员 int wheels;float weight;public:/公有函数成员 void initvehicle(int in_wheels,float in_weight);int get_wheels();float get_weight();/.;,class car:public vehicle/派生类car类的声明 private:/新增私有数据成员 int passenger_load;public:/新增公有函数成员 void initcar(int in_wheels,float in_weight,in

6、t people=4);int get_passengers();/.;,7.1.3 派生类生成过程 仔细分析派生新类这个过程,实际是经历了三个步骤:吸收基类成员,改造基类成员和添加新的成员。面向对象的继承和派生机制,其最主要的目的是实现代码的重用和扩充。因此,吸收基类成员就是一个重用的过程,而对基类成员进行调整、改造以及添加新成员就是原有代码的扩充过程,二者是相辅相成的。下面以某公司人员管理系统为例,分别对这几个步骤进行解释。基类employee和派生类technician声明如下,类的实现部分略去。,class employee protected:char*name;/姓名 int in

7、dividualEmpNo;/个人编号 int grade;/级别 float accumPay;/月薪总额 static intemployeeNo;/本公司职员编号目前最大值 public:employee();employee();void pay();/计算月薪函数 void promote(int);/升级函数 void displayStatus();/显示人员信息;,class technician:public employee private:float hourlyRate;/每小时酬金 int workHours;/当月工作时数 public:technician();/

8、构造函数 void pay();/计算月薪函数 void displayStatus();/显示人员信息;,1吸收基类成员 在类继承中,第一步是将基类的成员全盘接收,这样派生类实际上就包含了它的所有基类中除构造和析构函数之外的所有成员。注意,在派生过程中,构造函数和析构函数都不被继承。这里派生类technician继承了基类employee中除构造和析构函数之外的所有成员:name,individualEmpNo,grade,accumPay,employeeNo,pay(),promote(int),displayStatus()。经过派生过程,这些成员便存在于派生类之中。,2改造基类成员

9、第一是基类成员的访问控制,主要依靠派生类声明时的继承方式来控制。第二是对基类数据或函数成员的覆盖,就是在派生类中声明一个和基类数据或函数同名的成员,例如,上例中的pay()和displayStatus()。如果派生类声明了一个和某个基类成员同名的新成员(如果是成员函数,则参数表也要相同,参数不同的情况属于重载),派生的新成员就覆盖了外层同名成员。这时,在派生类中或者通过派生类的对象直接使用成员名就只能访问到派生类中声明的同名成员,这称为同名覆盖。在上例的程序中,派生类technician中的pay()和displayStatus()函数就覆盖了基类employee中的同名函数,3添加新的成员

10、派生类新成员的加入是继承与派生机制的核心,是保证派生类在功能上有所发展的关键。我们可以根据实际情况的需要,给派生类添加适当的数据和函数成员,以实现必要的新增功能。这里派生类technician中就添加了数据成员hourlyRate和workHours。,7.2 多继承,7.2.1多继承的声明 在派生类的声明中,基类名可以有一个,也可以有多个。如果只有一个基类名,则这种继承方式称为单继承;如果基类名有多个,则这种继承方式称为多继承,这时的派生类同时得到了多个已有类的特征。在多继承中,各个基类名之间用逗号隔开。多继承的声明语法如下:class:继承方式基类名1,继承方式基类名2,.,继承方式基类名

11、n 派生类成员声明;,例如,假设基类Basel、Base2是已经声明的类,下面的语句声明了一个名为MultiDerived的派生类,该类从基类Basel、Base2派生而来。class Base1/.;class Base2/.;class MultiDerived:public Base1,private Base2 public:MultiDerived();MultiDerived();/.;,图7-2 多继承和单继承,7.2.2 类族 一个基类可以同时派生出多个派生类。也就是说,一个类从父类继承来的特征也可以被其它新的类所继承,一个父类的特征,可以同时被多个子类继承。这样就形成了一个相

12、互关联的类的家族,称为类族。在类族中,直接参与派生出某类的基类称为直接基类;基类的基类甚至更高层的基类称为间接基类。图7-3所示为一个单继承的多层类族,其中A类派生出B类,B类又派生出E类,则B类是E类的直接基类,A类是B类的直接基类,而A类可以称为E类的间接基类。,图7-3 单继承类族示意图,7.3 类的继承方式,在面向对象程序中,基类的成员可以有public(公有)、protected(保护)和private(私有)三种访问属性。派生类继承了基类的全部数据成员和除了构造、析构函数之外的全部函数成员,但是这些成员的访问属性在派生的过程中是可以调整的。从基类继承的成员,其访问属性由继承方式控制

13、。类的继承方式有public(公有)继承、protected(保护)继承和private(私有)继承三种。对于不同的继承方式,会导致基类成员原来的访问属性在派生类中有所变化。表7-1列出了不同继承方式下基类成员各访问属性的变化情况(/test_inherit.cpp),表7-1 访问属性与继承的关系,7.3.1 公有继承 当类的继承方式为public(公有)继承时,基类的public(公有)和protected(保护)成员的访问属性在派生类中不变,而基类的private(私有)成员仍保持私有属性。也就是说,派生类的其它成员可以直接访问基类的公有成员和保护成员。其它外部使用者只能通过派生类的对象

14、访问继承来的公有成员。而无论是派生类的成员还是派生类的对象,都无法访问基类的私有成员。,【例7-1】公有继承例题。/test_inherit_public.cpp 从基类vehicle(汽车)公有派生car(小汽车)类,car类继承了vehicle类的全部特征,同时,car类自身也有一些特点,这就需要在继承vehicle类的同时添加新的成员。#include class vehicle/基类vehicle类的声明 private:/私有数据成员 int wheels;float weight;public:/公有函数成员 vehicle(int in_wheels,float in_weigh

15、t)wheels=in_wheels;weight=in_weight;int get_wheels()return wheels;float get_weight()return weight;,class car:public vehicle/派生类car类的声明 private:/新增私有数据成员 int passenger_load;public:/新增公有函数成员 car(int in_wheels,float in_weight,int people=5):vehicle(in_wheels,in_weight)passenger_load=people;int get_passe

16、ngers()return passenger_load;void main()car bluebird(4,1000);/car object coutbluebird.get_wheels()endl;/输出小汽车的信息 coutbluebird.get_weight()endl;coutbluebird.get_passenger()endl;,7.3.2 私有继承/test_inherit_private.cpp 当类的继承方式为private(私有)继承时,基类中的public(公有)成员和protected(保护)成员都以私有成员身份出现在派生类中,而基类的private(私有)成

17、员在派生类中不可访问。也就是说,基类的public成员和protected成员被继承后作为派生类的private成员,派生类的其它成员可以直接访问它们,但是在类外部通过派生类的对象无法访问。特别要注意,基类的private成员仍保持private属性,这样,无论是派生类的成员还是通过派生类的对象,都无法访问从基类继承的私有成员。,#includeclass vehicle/基类vehicle类的声明 private:/私有数据成员 int wheels;float weight;public:/公有函数成员 vehicle(int in_wheels,float in_weight)wheel

18、s=in_wheels;weight=in_weight;int get_wheels()return wheels;float get_weight()return weight;,【例7-2】私有继承例题。,class car:private vehicle/派生类car类的声明 private:/新增私有数据成员 int passenger_load;public:/新增公有函数成员car(intin_wheels,floatin_weight,intpeople=5):vehicle(in_wheels,in_weight)passenger_load=people;int get_w

19、heels()return vehicle:get_wheels();/重新定义get_wheels()float get_weight()return vehicle:get_weight();/重新定义get_weight()int get_passengers()return passenger_load;,void main()car bluebird(4,1000);/声明car类的对象coutThemessageofbluebird(wheels,weight,passengers):endl;coutbluebird.get_wheels(),/输出小汽车的信息bluebird.

20、get_weight(),bluebird.get_passengers()endl;,继承方式为私有继承。这时,基类中的公有和保护成员在派生类中都以私有成员的身份出现。派生类的成员函数及对象无法访问基类的私有数据(例如基类的wheels和weight)。派生类的成员仍然可以访问到从基类继承过来的公有和保护成员,但是在类外部通过派生类的对象根本无法访问到基类的任何成员,基类原有的外部接口(例如基类的get_wheels()和get_weight()函数)被派生类封装和隐蔽起来。当然,派生类新增的成员之间仍然可以自由地互相访问。在私有继承情况下,为了保证基类的部分外部接口特征能够在派生类中也存在

21、,就必须在派生类中重新定义同名的成员函数。,7.3.3 保护继承 保护继承中,基类的public(公有)和protected(保护)成员都以保护成员的身份出现在派生类中,而基类的private(私有)成员不可访问。具体说,基类中的保护成员只能被基类的成员函数或派生类的成员函数访问,不能被派生类以外的成员函数访问。,#include class vehicle/基类vehicle类的声明 private:/私有数据成员 int wheels;protected:/保护数据成员 float weight;public:/公有函数成员 vehicle(int in_wheels,float in_w

22、eight)wheels=in_wheels;weight=in_weight;int get_wheels()return wheels;float get_weight()return weight;,【例7-3】保护继承例题。/test_inherit_protected.cpp,class car:protected vehicle/派生类car类的声明 private:/新增私有数据成员 int passenger_load;public:/新增公有函数成员 car(int in_wheels,float in_weight,int people=5):vehicle(in_whee

23、ls,in_weight)passenger_load=people;int get_wheels()return vehicle:get_wheels();/重新定义get_wheels()float get_weight()return vehicle:get_weight();/重新定义get_weight()intget_passengers()returnpassenger_load;,void main()car bluebird(4,1000);/声明car类的对象 coutThe message of bluebird(wheels,weight,passengers):end

24、l;coutbluebird.get_wheels(),/输出小汽车的信息 bluebird.get_weight(),bluebird.get_passengers()endl;,在例7-3中,我们将例7-2中私有数据成员weight改为保护数据成员,类定义的其它部分没改变,继承方式改为保护继承。这时,基类中的公有和保护成员在派生类中都以保护成员的身份出现。派生类的成员函数及对象无法访问基类的私有数据和保护数据(例如基类的wheels和weight)。派生类的成员仍然可以访问到从基类继承过来的公有和保护成员。同私有继承一样,在保护继承情况下,为了保证基类的部分外部接口特征能够在派生类中也存在

25、,就必须在派生类中重新定义同名的成员函数。这里在派生类car中,重新定义了get_wheels()和get_weight()函数。根据同名覆盖的原则,在主函数中自然调用的是派生类的函数。,可以看出在直接派生类中,所有成员的访问属性都是完全相同的。但是,如果派生类作为新的基类继续派生时,二者的区别就出现了。如图7-4所示。图中7-4(a)说明B类以私有方式继承了A类后,又派生出C类,则C类的成员和对象都不能访问间接从A类中继承来的成员。图7-4(b)说明B类以保护方式继承了A类,那么A类中的公有和保护成员在B类中都是保护成员。,图7-4 类的保护成员的访问规则(a)私有继承(b)保护继承,7.4

26、 派生类的构造和析构函数,7.4.1 构造函数 派生类对象的初始化也是通过派生类的构造函数实现的。具体来说,就是对该类的数据成员赋初值。派生类的数据成员由所有基类的数据成员与派生类新增的数据成员共同组成,如果派生类新增成员中包括有内嵌的其它类对象,派生类的数据成员中实际上还间接包括了这些对象的数据成员。因此,初始化派生类的对象时,就要对基类数据成员、新增数据成员和成员对象的数据成员进行初始化。因此,派生类的构造函数需要以合适的初值作为参数,隐含调用基类和新增的内嵌对象成员的构造函数来初始化它们各自的数据成员,然后再加入新的语句对新增普通数据成员进行初始化。,派生类构造函数声明的一般语法形式如下

27、::(参数总表):基类名1(参数表1),.,基类名n(参数表n),内嵌对象名1(内嵌对象参数表1),.,内嵌对象名m(内嵌对象参数表m)派生类新增成员的初始化语句;其中:派生类的构造函数名与派生类名相同。参数总表需要列出初始化基类数据、新增内嵌对象数据及新增一般成员数据所需要的全部参数。冒号之后,列出需要使用参数进行初始化的基类名和内嵌成员名及各自的参数表,各项之间用逗号分隔。,#include class vehicle/基类vehicle的声明 private:int wheels;float weight;public:/基类vehicle的构造函数 vehicle(int in_whe

28、els,float in_weight)wheels=in_wheels;weight=in_weight;/.;,派生类构造函数的执行顺序一般是,先祖先(基类),再客人(内嵌对象),后自己(派生类本身)。例:,class car:public vehicle/派生类car的声明 private:/新增私有数据成员 int passenger_load;public:/派生类car的构造函数 car(int in_wheels,float in_weight,int people=4):vehicle(in_wheels,in_weight)passenger_load=people;/.;v

29、oid main()car bluebird(4,3);/声明派生类car的对象/.,7.4.2 析构函数 在派生过程中,基类的析构函数不能继承,如果需要析构函数的话,就要在派生类中重新定义。析构函数没有类型,也没有参数,和构造函数相比,情况略为简单。派生类析构函数的定义方法与没有继承关系的类中析构函数的定义方法完全相同,只要在函数体中负责把派生类新增的非对象成员的清理工作做好就够了,系统会自己调用基类及成员对象的析构函数来对基类及对象成员进行清理。但它的执行顺序和构造函数正好严格相反先自己(派生类本身),再客人(内嵌对象),后祖先(基类)。,【例7-4】派生类的构造函数和析构函数(多继承,含

30、有内嵌对象),#include/class Base1/基类Base1,构造函数有参数 public:Base1(int i)coutconstructing Base1iendl;Base1()coutdestructing Base1endl;/Base1的析构函数;class Base2/基类Base2,构造函数有参数 public:Base2(int j)coutconstructing Base2jendl;Base2()coutdestructing Base2endl;/Base2的析构函数;class Base3/基类Base3,构造函数无参数 public:Base3()co

31、utconstructing Base3endl;Base3()coutdestructing Base3endl;/Base3的析构函数;,class Derive:public Base2,public Base1,public Base3/派生新类 private:/派生类新增私有对象成员 Base1 memberBase1;Base2 memberBase2;Base3 memberBase3;public:/派生类的构造函数Derive(inta,intb,intc,intd):Base2(b),memberBase2(d),memberBase1(c),Base1(a);void

32、main()Derive object(2,4,6,8);,考虑Derive类的构造函数的执行情况。它应该是先调用基类的构造函数,然后调用内嵌对象的构造函数。基类构造函数的调用顺序是按照派生类声明时的顺序,因此,应该是先Base2,再Base1,再Base3。而内嵌对象的构造函数的调用顺序应该是按照成员在类中声明的顺序,应该是先Base1,再Base2,再Base3。程序运行的结果也完全证实了这种分析。程序运行结果为 constructing Base2 4 constructing Base1 2 constructing Base3 constructing Base1 6 constru

33、cting Base2 8 constructing Base3,destructing Base3 destructing Base2destructing Base1destructing Base3destructing Base1destructing Base2,7.5 派生中成员的标识与访问,7.5.1 作用域分辨 在派生类的访问中,有两个问题需要解决:第一是唯一标识问题;第二是可见性问题。对于在不同的作用域声明的标识符,其可见性原则是:如果存在两个或多个具有包含关系的作用域,并且外层声明的标识符如果在内层没有声明同名的标识符,那么它在内层仍可见;如果内层声明了同名的标识符,则外层

34、标识符在内层不可见,这时称内层变量覆盖了外层同名变量,这种现象称为同名覆盖。1作用域分辨符 作用域分辨符就是我们经常见到的“:”,它可以用来限定要访问的成员归属哪个类,其一般的使用形式如下::(参数表)在类的派生层次结构中,基类的成员和派生类新增的成员都具有类作用域。二者的作用范围不同,是相互包含的两个层,派生类在内层。,【例7-5】继承中使用作用域分辨符例题。#include class Base/声明基类Base public:int n;void fun()coutThis is Base,n=nendl;class Derive:public Base/声明派生类Derive publ

35、ic:int n;/同名数据成员 void fun()coutThis is Derive,n=nendl;/同名函数成员;,void main()Derive obj;obj.n=1;/对象名.成员名标识obj.fun();/对象名.成员函数名标识obj.Base:n=2;/作用域分辨符标识obj.Base:fun();/访问Base基类成员,程序运行结果为 This is Derive,n=1 This is Base,n=2,2.多继承中作用域分辨符的使用 在多继承中,如果某个派生类的部分或全部直接基类是从另一个共同的基类派生而来,在这些直接基类中,从上一级基类继承来的成员就拥有相同的名

36、称。因此,派生类中也就会产生同名现象。对这种类型的同名成员也要使用作用域分辨符来唯一标识,而且必须用直接基类来进行限定。我们再来看一个例题。,【例7-6】多继承中使用作用域分辨符例题。类的派生关系及派生类的结构见图7-5。,图7-5多重继承情况下派生类Level3继承关系、成员构成图(a)继承关系(b)Level3类结构,int Level22:n1,现在我们来讨论同名成员n1和fun1()的标识与访问问题。间接基类Level1的成员经过两次派生之后,通过不同的派生路径以相同的名字出现在派生类Level3中。这时,如果使用基类名Level1来限定,同样无法表明成员到底是从Level21还是Le

37、vel22继承过来的,因此,必须使用直接基类Level21或者Level22的名称来限定,才能够唯一标识和访问成员。/test_derive1.cpp 程序代码如下:#include class Level1/声明基类Level1 public:int n1;void fun1()coutThis is Level1,n1=n1endl;,class Level21:public Level1/声明派生类Level21 public:int n21;class Level22:public Level1/声明派生类Level22 public:int n22;class Level3:publ

38、ic Level21,public Level22/声明派生类Level3 public:int n3;void fun3()coutThis is Level3,n3=n3endl;,void main()Level3 obj;obj.n3=1;obj.fun3();obj.Level21:n1=2;/使用直接基类obj.Level21:fun1();/使用直接基类obj.Level22:n1=3;/使用直接基类obj.Level22:fun1();/使用直接基类 在程序主函数中,创建了一个派生类的对象obj。如果只通过成员名称来访问该类的成员n1和fun1(),系统就无法唯一确定要引用的成

39、员。这时,必须使用作用域分辨符,通过直接基类名来确定要访问的从基类继承来的成员。程序运行结果为 ThisisLevel3,n3=1 ThisisLevel1,n1=2 ThisisLevel1,n1=3,这种情况下,派生类对象在内存中就同时拥有成员n1及fun1()的两份同名拷贝。对于数据成员来讲,两个n1可以分别通过Level21和Level22调用Level1的构造函数进行初始化,可以存放不同的数值,也可以使用作用域分辨符通过直接基类名的限定来分别进行访问。但是在很多情况下,我们只需要一个这样的数据拷贝,同一成员的多份拷贝增加了内存的开销。C+提供了虚基类技术来解决这一问题,这部分内容将在

40、7.6节中介绍。,7.5.2 基类私有成员的访问 不管是私有派生还是公有派生,派生类都无权访问基类的私有成员。派生类想要使用基类的私有成员,只能通过调用基类的成员函数来实现,也就是使用基类所提供的接口。对于需要频繁访问基类私有成员的派生类来说,这种方式使用起来非常不方便。因此,需要寻求直接访问基类私有成员的方式。有两种方式可供选择,下面分别介绍。1.在类定义体中增加保护段 保护段成员可以被它的派生类访问,但是对于外界是隐藏的。这样,即方便了派生类的访问,又禁止了外界对它的操作。例:,程序代码如下:#includeclass vehicle/基类vehicle类的声明 protected:/保护

41、数据成员 int wheels;float weight;public:/公有函数成员 vehicle(int in_wheels,float in_weight)wheels=in_wheels;weight=in_weight;int get_wheels()return wheels;float get_weight()return weight;float wheel_load()return weight/wheels;void print();,class car:vehicle/派生类car类的声明 private:/新增私有数据成员 int passenger_load;pub

42、lic:/新增公有函数成员 car(int in_wheels,float in_weight,int people=4):vehicle(in_wheels,in_weight)passenger_load=people;int get_passengers()return passenger_load;void print();,class struck:vehicle/派生类truck类的声明 private:/新增私有数据成员 int passenger_load;float payload;public:/新增公有函数成员 truck(int in_wheels,float in_w

43、eight,int people=2,float max_load=24000.00):vehicle(in_wheels,in_weight)passenger_load=people;payload=max_load;int get_passengers()return passenger_load;float efficiency()return payload/(payload+weight);void print();,void vehicle:print()/输出汽车类vehicle的数据 coutthe wheels of vehicleiswheelsendl;coutthe

44、weight of vehicleisweightendl;coutendl;void car:print()/输出小车类car的数据 coutthe wheels of cariswheelsendl;coutthe weight of carisweightendl;coutthe passenger_load of carispassenger_loadendl;coutendl;void truck:print()/输出卡车类truck的数据 coutthe wheels of truc k iswheelsendl;coutthe weight of truck isweighten

45、dl;coutthe passenger_load of truckispassenger_loadendl;coutthe efficency of truckisefficiency()endl;coutendl;,void main()car bluebird(4,1000,5);/声明car类的对象 truck dongfeng(10,5000,3,34000);/声明truck类的对象 bluebird.print();dongfeng.print();,程序运行结果为The wheels of car is 4The weight of car is 1000The passeng

46、er_load of car is 5The wheels of truck is 10The weight o f truck is 5000The passenger_load of truck is 3The efficiency of truck is 0.871795,2将需访问基类私有成员的派生类成员函数声明为基类的友元另一种访问基类私有成员的方法是将待访问的成员函数声明为基类的友元,这样,派生类中的其它成员函数都无权访问它,外界更不可能通过派生新类来访问基类的私有成员。关于友元函数在前面第5章已介绍过,这里就不再赘述。,#include#include class string

47、private:char*name;int length;public:string(char*str)length=strlen(str);name=new charlength+1;strcpy(name,str);void show()coutnameendl;,7.5.3 引入派生类后的对象指针【例7-8】引入派生类后的对象指针例题。,class de_string:public string private:int age;public:de_string(char*str,int age):string(str)de_string:age=age;void show()string

48、:show();coutthe age is:ageendl;,main()string s1(Smith),*ptr1;/定义string类对象s1及指针ptr1 de_string s2(Jean,20),*ptr2;/定义de_string类对象s2及指针ptr2 ptr1=,程序运行结果为 Smith Jean Jean theageis:20 从本例可以看出,虽然ptr1指针已经指向了s2对象(ptr1=&s2),但是它所调用的函数(ptr1-show()仍然是其基类对象的成员函数。这是使用时要注意的问题。在使用引入派生类之后的对象指针时,要特别注意下面几点。,可以用一个声明指向基类

49、对象的指针指向它的公有派生的对象,若试图指向它的私有派生的对象则是被禁止的。例如:class Base/定义基类Base/.;class Derive:Base/定义基类Base的私有派生类Derive/.;main()Base obj1,*ptr1;Derive obj2;ptr1=,不能将一个声明为指向派生类对象的指针指向其基类的对象。例如:class Base/定义基类Base/.;class Derive:public Base/定义基类Base的公有派生类Derive/.;main()Base obj1;Derive obj2,*ptr;ptr=,声明为指向基类对象的指针,当其指向派

50、生类对象时,只能利用它来直接访问派生类中从基类继承来的成员,不能直接访问公有派生类中特定的成员。例如:class Base/定义基类Base public:void show1();class Derive:public Base/定义基类Base的公有派生类Derive void show2();main()Base obj1,*ptr;Derive obj2;ptr=,ptr-show2();/错误!试图调用派生类的特定成员/.return1;若想访问其公有派生类的特定成员,可以将基类指针显式类型转换为派生类指针来实现。,在公有继承前提下,除了派生类对象的地址可以赋给指向基类的指针,派生类

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号