版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C++语言设计
第五章继承与派生大连海事大学陈余庆第一章C++的初步知识第二章类和对象第三章再论类和对象第四章运算符重载第五章继承与派生第六章多态性与虚函数第七章输入输出流第八章C++工具5.1继承与派生的概念5.2派生类的声明方式5.3派生类的构成5.4派生类成员的访问属性5.5派生类的构造函数和析构函数5.6多重继承5.7基类与派生类的转换5.8继承与组合5.1继承与派生的概念 我们知道,面向对象程序设计的4个特性有抽象、封装、继承和多态。我们已经讨论了数据的抽象性和封装性,现在来讨论数据的继承。
5.1继承与派生的概念 所谓继承,就是根据一个已存在的类建立一个新的类。已存在的类叫“基类”或“父类”,新建立的类叫“派生类”或“子类”。 新建立的子类从基类那里获得基类的特性,称为类的继承;由基类产生新的子类,叫派生。一个基类可以派生多个子类,一个子类可以由多级基类派生而来。比方:大学学生大学生研究生大专生本科生博士生硕士生一个基类派生多级子类示意图约定:箭头方向表示继承的方向,由派生类指向基类。5.1继承与派生的概念多个基类派生一个子类示意图。约定:箭头方向表示继承的方向,由派生类指向基类。研究生职工在职研究生基类:派生类:5.2派生类的声明方式声明派生类的方法:
class派生类名:[继承方式]基类名
{派生类新增的成员 };继承方式包括:Public方式,公用方式;Private方式,私有方式;Protected方式,受保护方式。继承方式是可选的,不写此项,默认为私有方式。5.2派生类的声明方式 例如,由一基类Box〔盒子类〕,派生出一个新的子类colorBox〔彩色盒子〕:#include<iostream.h>classBox{private:intlen,wid,hei;public:voiddisplay(){cout<<“盒子体积=”<<len*wid*hei<<endl;}Box(intl=0,intw=0,inth=0){len=l;wid=w;hei=h;}};classcolorBox:publicBox{private:intcolor;public:voiddisplay(){cout<<“盒子的颜色=”<<color<<endl;}colorBox(intc=0){color=c;}};voidmain(){colorBoxcb1(3);cb1.display();}colorBox类intlen;intwid;inthei;构造函数Box;voiddisplay();intcolor;voiddisplay();Box类intlen;intwid;inthei;构造函数Box;voiddisplay();5.3派生类的构成 派生类的成员包括从基类继承过来的成员和自己增加的成员。从基类继承过来的成员,表达了基类与子类的共性;而新增加的成员,表达了子类的个性。下面是Box基类和colorBox子类的存储图:基类数据成员成员函数派生类新增成员继承5.3派生类的构成 请注意,类的继承并不是把基类成员和派生类新增成员简单地放在一起。构造一个派生类包括以下四局部工作从基类接收成员。派生类把基类的全部成员〔不包括构造函数和析构函数〕接收过来。缺乏之处在于会造成冗余,浪费存储空间和执行效率,尤其是屡次派生时。所以,不能随意地找一个类去派生出某一个子类。调整从基类接收的成员。接收基类成员必须照单全收,但编程人员可以对接收过来的成员作一些调整。如,通过指定不同的继承方式,来改变基类成员在派生类中的访问属性;在派生类中声明一个和基类成员同名的成员,来“遮盖”接收的基类成员。如果想遮盖成员函数,其函数名和参数表必须相同,否那么就成为重载。在声明派生类时增加新的成员。主要表达子类对基类的扩展。构造派生类的构造函数和析构函数。5.4派生类成员的访问属性 派生类成员中包含基类成员和派生类成员,在讨论访问属性时,需要考虑以下几种情况:基类成员函数访问基类成员;派生类成员函数访问派生类自己新增成员;基类成员函数访问派生类成员;派生类成员函数访问基类成员;在派生类外访问派生类的成员;在派生类外访问基类的成员。 对于①、②,种情况,按照第二章介绍的规那么处理。即基类成员函数可访问基类成员,派生类成员函数可访问派生类自己新增成员,基类私有数据成员只能被基类成员函数访问,派生类新增私有数据成员,只能被派生类新增成员函数访问。5.4派生类成员的访问属性 对于第④~⑥种情况,我们分不同的继承方式分开讨论:公用继承:基类的公用成员和保护成员在派生类中保持原有的访问属性,其私有成员仍为基类的私有,派生类新增成员不可访问它。私有继承:基类的公用成员和保护成员在派生类中成为私有成员,其私有成员仍为基类的私有,派生类新增成员不可访问它。保护继承:基类的公用成员和保护成员在派生类中成为保护成员,其私有成员仍为基类的私有,派生类新增成员不可访问它。什么叫保护成员? 保护成员不能被外界引用,但可以被派生类的成员引用。5.4派生类成员的访问属性公用继承公用继承的定义:在定义一个派生类时,将基类的继承方式指定为public就是公用继承。其基类叫公用基类(publicbaseclass),子类叫公用派生类(publicderivedclass)。被公用继承而来的基类在派生类中的访问属性见下表: 我们来看看下面的例如程序:公用基类的成员在公用派生类中的访问属性私有成员不可访问公用成员公用保护成员私有5.4派生类成员的访问属性#include<iostream.h>#include<string.h>classperson{public:voidget_value(){cin>>num>>name;}voiddisplay(){cout<<“id:”<<num<<endl;cout<<“name:”<<name<<endl;}private:intnum;stringname;};classstudent:publicperson{public:voiddisplay(){cout<<“id:”<<num<<endl;//错误,派生类中不能访问基类私有成员cout<<“name:”<<name<<endl;//错误,派生类中不能访问基类私有成员cout<<“stu_id:”<<stu_id<<endl;}private:intstu_id;};程序应修改,在main函数中分别调用基类和派生类的显式成员函数:#include<iostream.h>#include<string.h>classperson{public:voidget_value(){cin>>num>>name;}voidperson_display(){cout<<“id:”<<num<<endl;cout<<“name:”<<name<<endl;}private:intid;stringname;};classstudent:publicperson{public:voidstudent_display(){cout<<“stu_id:”<<stu_id<<endl;}private:intstu_id;};voidmain(){studentzhangsan;:::zhangsan.person_display();zhangsan.student_display();} 这里只是对显示函数做了调整,其实还有很多修改.比方,对数据输入,就要调整.请同学们自己完成.5.4派生类成员的访问属性私有继承私有继承的定义:在定义一个派生类时,将基类的继承方式指定为private就是私有继承。其基类叫私有基类(privatepublicbaseclass),子类叫私有派生类(privatederivedclass)。被私有继承而来的基类在派生类中的访问属性见下表: 我们来看看下面的例如程序:私有基类的成员在私有派生类中的访问属性私有成员不可访问公用成员私有保护成员私有5.4派生类成员的访问属性 我们作如下示意图来说明私有继承的访问属性:子类Bpublic:intm;private:inti,n;不可访问:intk;基类Apublic:inti;private:intk;子类Bpublic:inti;private:intk;public:intm;private:intn;私有继承派生类新增成员实际派生类基类A中的公用成员i,私有成员k,被私有派生给子类B子类B自己新增公用成员m,和私有成员n最后,子类B具有的公用成员为m,私有成员为i,n。基类的k在子类B中不可访问。私有继承例如:这里的错误该如何改写?#include<iostream.h>#include<string.h>classperson{public:voidget_value(){cin>>num>>name;}voidperson_display(){cout<<“id:”<<num<<endl;cout<<“name:”<<name<<endl;}private:intnum;stringname;};classstudent:privateperson{public:voidstudent_display(){cout<<“stu_id:”<<stu_id<<endl;}private:intstu_id;};voidmain(){studentzhangsan;:::zhangsan.person_display();//私有继承基类的公用函数//变成子类私有函数,类外不能访问zhangsan.student_display();}
可以将子类的显示函数这样改写:#include<iostream.h>#include<string.h>classperson{public:voidget_value(){cin>>num>>name;}voidperson_display(){cout<<“id:”<<num<<endl;cout<<“name:”<<name<<endl;}private:intid;stringname;};classstudent:privateperson{public:voidstudent_display(){person_display();
cout<<“stu_id:”<<stu_id<<endl;}private:intstu_id;};voidmain(){studentzhangsan;:zhangsan.student_display();}5.4派生类成员的访问属性保护成员和保护继承 “保护,protected”既可以用来限定类成员的性质,也可以用来限定继承方式。保护成员:被protected声明的成员叫保护成员,保护成员不能被类外访问,这和私有成员的特性一样;但保护成员如果被派生给子类,可以被子类的成员函数引用。 我们将友元比喻成朋友,可以进入自己的卧室,访问类的私有成员;我们将保护成员比喻成保险箱,任何外人不得窥视,包括朋友。只有自己和子女〔即派生类〕可以翻开。保护继承:派生类继承时被指定为protected。用保护方式继承的派生类叫保护派生类(protecteddetivedclass),其基类叫受保护的基类(protectedbassclass)。 保护继承的特点是,保护基类的公用成员和和保护成员在保护派生类中成为保护成员,私有成员仍为基类私有,派生类不得引用。5.4派生类成员的访问属性 综合所述,三种继承方式下派生类成员的访问属性列表如下:基类中的成员属性在公用继承得来的派生类中在私有继承得来的派生类中在保护继承得来的派生类中私有成员不可访问不可访问不可访问公用成员公用私有保护保护成员保护私有保护由上表可以得出以下结论:公用成员,派生类内外都可以访问;保护成员,派生类内可以访问,派生类外不能访问,其下一级的派生也可以访问;私有成员,派生类内可以访问,派生类外不能访问,其下一级的派生不可访问;不可访问的成员,派生类内外都不可访问。5.4派生类成员的访问属性 下面是一个怎样使用保护成员的例如:#include<iostream.h>#include<string.h>classperson{protected:intid;stringname;};classstudent:protectedperson{public:voidstudent_display(){cout<<“id:”<<id<<endl;cout<<“name:”<<name<<endl;cout<<“stu_id:”<<stu_id<<endl;}private:intstu_id;};voidmain(){studentzhangsan;student.id=“12345678;//错误,外界不能访问保护成员zhangsan.student_display();//合法,此函数是公用函数}5.4派生类成员的访问属性多级派生时的访问属性 实际应用中,常常有多级派生的情况。比方:A是基类,派生出B类,B类又派生出C类。那么B是A的直接派生,C是A的间接派生。A是B的直接基类,A是C的间接基类。请看:A是B的公用基类,B是C的保护基类;各成员在不同类的属性为:classA{public:inti;protected:intj;voidf2();private:intk;};classB:publicA{public:voidf3();protected:voidf4();private:intm;};classC:protectedB{public:voidf5();private:intn;};if2jkf3f4mf5n基类A公用保护保护私有公用派生类B公用保护保护不可访问公用保护私有保护派生类C保护保护保护不可访问保护保护不可访问公用私有5.4派生类成员的访问属性上表说明:无论哪一种继承方式,在派生类中不能访问基类的私有成员,私有成员只能被本类的成员函数访问;多级派生假设都采用公用继承,直到最后一级派生类都能访问基类的公用成员和保护成员;多级派生假设都采用私有继承,经过假设干次派生后,基类的所有成员都变成不可访问;多级派生假设都采用保护继承,派生类外无法访问派生类中的任何成员,人们很难记住哪些成员还能访问,哪些成员不能被访问。 因此,实际应用中,通常采用公用继承方式。5.5派生类的构造函数和析构函数 构造函数的主要作用是对数据成员初始化。在第三章我们介绍过,用户在声明类时可以不定义构造函数,系统会自动设置一个默认的构造函数,在定义类对象时会自动调用这个默认的构造函数。这个默认的构造函数实际上是个空函数,不执行任何操作,如果需要初始化对象的数据成员,应该自己定义构造函数。 我们已经知道,基类的构造函数是不能继承的。因此,对继承来的基类成员初始化的工作,要由派生类的构造函数承担。所以,在设计派生类的构造函数时,不仅要考虑初始化派生类自己新增的数据成员,还要考虑初始化基类的数据成员。 解决问题的思路是:在执行派生类的构造函数时,调用基类的构造函数。5.5派生类的构造函数和析构函数简单派生类的构造函数 我们说的“简单”是指,一个基类直接派生出一个子类,派生类的数据成员中不包含基类的对象〔即子类〕。简单派生类的构造函数一般形式 派生类构造函数名(总参数表列):基类构造函数名(参数表列) {派生类中新增数据成员初始化语句} 下面以一个派生类的实例来说明有些什么东西。5.5派生类的构造函数和析构函数#include<iostream.h>#include<string.h>classperson//基类声明{public:person(inti,stringnam)//基类构造函数{id=i;name=nam;}protected:intid;stringname;};classstudent:publicperson//声明公用派生类{public:
student(inti,stringnam,intsid):person(i,nam){stuid=sid;}//子类构造函数voidshow(){cout<<“id:”<<id<<endl;cout<<“name:”<<name<<endl;cout<<“stuid:”<<stuid<<endl;}private:intstuid;};voidmain(){students1(1234,”张三”,200701);s1.show();}5.5派生类的构造函数和析构函数 将派生类的构造函数形式与第三章介绍的“用参数初始化表对数据成员初始化”的介绍,对照看看:
student(inti,stringnam,intsid):person(i,nam){stuid=sid;} box::box(inth,intw,intlen):height(h),width(w),length(len){}
它也有一个冒号,在冒号后面是对数据成员的初始化表。很相似吧? 实际上,本章介绍的在派生类构造函数中对基类成员初始化,就是第三章介绍的构造函数初始化表。也就是说:不仅可以用初始化表对数据成员初始化,而且可以利用初始化表调用派生类的基类构造函数,实现对基类数据成员的初始化。也可以在同一个构造函数中同时实现这两种功能。5.5派生类的构造函数和析构函数 例如,我们可以将上一个例如的子类构造函数改写成这样: student(inti,stringnam,intsid):person(i,nam),stuid(sid){} 这样,函数体为空,显得很简捷,方便。在建立一个对象时,执行构造函数的顺序是:先调用基类构造函数;再执行派生类自身的构造函数。 对于刚刚的例如,先初始化id,name,再初始化stuid。5.5派生类的构造函数和析构函数有子对象的派生类的构造函数 如果类的数据成员除了标准数据类型外,还包含类对象,这种被包含的对象就叫“子对象(subobject),即对象中的对象。 我们仍以学生类为例如。在person的派生类student中,出来增加学号stuid,还增加“家长parent”一项,即学生数据中包含他的家长姓名等相关情况,而家长本身也属于person类型,这样,家长parent项既是基类person对象,也派生类student的子对象。 那么,初始化子类对象的数据成员时,怎样对它所包含的子对象初始化呢?这是我们所关心的问题。请看下面程序:5.5派生类的构造函数和析构函数#include<iostream.h>#include<string.h>classperson{public:person(inti,stringnam){id=i;name=nam;}
voiddisplay(){cout<<“id:”<<id<<endl;cout<<“name:”<<name<<endl;}protected:intid;stringname;};classstudent:publicperson
{public:
student(inti,stringnam,intpid,stringpnam,intsid):person(i,nam),parent(pid,pnam){stuid=sid;}派生类构造函数任务:1,初始化基类数据成员;2,初始化子对象数据成员;3,初始化派生类新增数据成员。voidshow(){cout<<“id:”<<id<<endl;cout<<“name:”<<name<<endl;cout<<“stuid:”<<stuid<<endl;}voidshowParent(){cout<<“parent_id:”<<endl;parent.display();}private:intstuid;
personparent;};voidmain(){students1(1234,”张三”,2211,”张父”,200701);s1.show();
s1.showParent();}5.5派生类的构造函数和析构函数 归纳起来,我们有派生类构造函数的一般形式:
派生类构造函数名(总参数表):
基类构造函数名(参数表列), 子对象名(参数表列),
{派生类中新增数据数据成员初始化语句}执行派生类构造函数的顺序:调用基类构造函数,初始化基类数据成员;调用子对象构造函数,初始化子对象数据成员;再执行派生类自身的构造函数,初始化自己新增数据成员。5.5派生类的构造函数和析构函数 上例中的student派生类构造函数可写成如下形式:
student(inti,stringnam,intpid,stringpnam,intsid): person(i,nam), parent(pid,pnam), stuid(sid){}
可以看到,函数体为空。此时,派生类构造函数参数个数等于基类构造函数参数、子对象构造函数参数、自己新增数据对象初始化参数之和。这种形式十分常见。5.5派生类的构造函数和析构函数多层派生时的构造函数 当出现多层派生时,不能列出每一层的构造函数,只须写出其上一层派生类〔即它的直接基类〕的构造函数就可以了。private:intage;};classstudent2:publicstudent1{public:
student2(intn,stringnam,inta,ints):student1(n,nam,a){score=s;}voidshow_all(){show();cout<<“age:”<<age<<endl;}private:intscore;};voidmain(){student2stud(1001,”Li”,17,90);stud.show_all();}#include<iostreaam.h>#include<string.h>classstudent{public:student(intn,stringnam){num=n;name=nam;}voiddisplay(){cout<<“num:”<<num<<endl;cout<<“name:”<<name<<endl;}private:intnum;stringname;};classstudent1:publicstudent{public:student1(intn,stringnam,inta):student(n,nam){age=a;}voidshow(){display();cout<<“age:”<<age<<endl;}5.5派生类的构造函数和析构函数 程序中,基类student构造函数首部为:
student(intn,stringnam) 一级派生类student1构造函数首部为
student1(intn,stringnam,inta):student(n,nam) 二级派生类student2构造函数首部为
student2(intn,stringnam,inta,ints
):student1(n,nam,a)
注意,二级派生类student2构造函数首部不要写成:
student2(intn,stringnam,inta,ints
):student(n,nam),student1(n,m,a)//错误!!
不要列出每一层构造函数,只须列出其上一层的构造函数。5.5派生类的构造函数和析构函数派生类的析构函数析构函数的作用:我们已经学过,析构函数的作用是在撤消对象之前,给编程人员一个时机,来进行一些清理工作。当对象被删除时,系统会自动调用析构函数。 和构造函数一样,析构函数也是不能派生给派生类的,在派生类中必须编写自己的析构函数,来作些派生类自己的清理工作。调用析构函数的顺序:与调用构造函数的顺序正好相反:先执行派生类自己的析构函数,清理派生自己新增数据成员;再调用子对象的析构函数,清理子对象;最后调用基类的析构函数,对基类进行清理。5.6多重继承什么叫多重继承?一个子类由多个基类派生而来,叫多重继承。比方所,在职研究生,既有在职职工的属性,又有研究生的属性。C++为了适应这种情况,允许一个派生类同时继承多个基类,这种行为就是多重继承(multipleinheritance)。声明多重继承的方法:设已声明了类A,B,C,可以从它们派生出子类D,其声明的一般形式为: classD:publicA,privateB,protectedC {类D新增加的成员} D是按照不同的继承方式从不同的基类多重继承而来的派生类。5.6多重继承多重继承派生类的构造函数:多重继承派生类的构造函数与单继承派生类的构造函数根本相同,只是在初始表中包含多个基类构造函数。其一般形式是: 派生类构造函数名(总参数表): 基类1构造函数(参数列表1), 基类2构造函数(参数列表2), 基类3构造函数(参数列表3) {派生类中新增数据成员初始化语句} 例:分别声明一个职工类(姓名,工资)和一个研究生类(姓名,成绩),用多重继承的方式从这两个类派生出在职研究生类(新增学号)。在定义派生类时给出初始化数据,然后输出这些数据。5.6多重继承#include<iostream>#include<string>usingnamespacestd;classworker{public:worker(stringnam,intsal){name=nam;salary=sal;}voidwdisplay(){cout<<“name:”<<wname<<endl;cout<<“salary:”<<salary<<endl;}protected:stringwname;intsalary;};classstudent{public:student(stringsnam,ints)
{sname=snam;score=s;}voidsdisplay(){cout<<“name:”<<sname<<endl;cout<<“score:”<<score<<endl;}protected:stringsname;intscore;};classgraduate:publicworker,publicstudent{public:graduate(stringnam,intsal,ints,inti):worker(nam,sal),student(nam,s),id(i){}voidgdisplay(){cout<<“id:”<<id<<endl;cout<<“wname:”<<name<<endl;cout<<“salary:”<<salary<<endl;cout<<“score:”<<score<<endl;}private:intid;};voidmain(){graduates1(“Li”,2000,90,1001);s1.gdisplay();}
5.6多重继承 此例程中,请注意:两个基类的数据成员都声明成protected类型,因此可以通过派生类的成员函数引用这两个基类的数据成员。同学们可能注意到,两个基类中,分别用wname和sname来表示姓名,其实是同一个人的姓名,能否用同一名称呢?不行。因为,这样一来,同一个派生类中就有两个同名的数据成员,引起二义性。多重继承时,从不同的基类中会继承一些重复的数据,例如本例中姓名就是重复的。在实际编程应用中,会有更多的重复数据,问题会更突出。5.6多重继承多重继承的二义性 多重继承给编写程序带来灵活性,但也引出了“二义性(ambiguous)”问题。我们来看看。 假设类A和类B中都有成员函数display和数据成员a,类C是A、B的多重继承的直接派生类。我们以下三种情况讨论:两个基类有同名成员, 如右图示。假设C 类有一对象c1, 我们写: c1.a=3; c1.display();A类inta;voiddisplay()B类inta;voiddisplay()C类inta;voiddisplay()inta;voiddisplay()intb;voidshow()基类A的成员基类B的成员派生类C新增成员5.6多重继承 由于基类A、B都有数据成员a,和成员函数display(),系统没法判断要访问哪一个基类成员。解决的方法是,在成员名前加上对象名来限制: c1.A::a=3; c1.A::display(); 如果在派生类C中,通过成员函 数show()来访问基类的display()和 a,可以直接写成: A::a=3; A::display();C类intA::a;voidA::display()intB::a;voidB::display()intb;voidshow()基类A的成员基类B的成员派生类C新增成员5.6多重继承两个基类和派生类都有同名成员,那么C类的成员函数变为: classC:publicA,publicB {inta; voiddisplay(); }在main函数中,定义C对象为c1,并调用a和dispaly():Cc1;c1.a=3;c1.display(); 这访问的是C的成员,因为有规那么:基类的同名成员在派生类中被屏蔽。C类intA::a;voidA::display()intB::a;voidB::display()inta;voiddisplay()基类A的成员基类B的成员派生类C新增成员5.6多重继承如果类A、B是从同一个基类派生的,如以下图示: 基类N的成员a和display()在一级派生类A、B中都存在。假设要访问A类中的a和display(),必须加上类名限定。类N类A类B类CclassC:publciA,publicB{public:inta3;voidshow(){cout<<“a3:“<<a3<<endl;}};voidmain(){Cc1;c1.A::a=3;c1.A::display();}classN{public:inta;voiddisplay(){cout<<“N::a:”<<a<<endl;}};classA:publicN{public:inta1;};classB:publicN{public:inta2;};5.6多重继承虚基类 如果一个派生类有多个直接基类,而这些直接基类又有一个共同的基类,那么在最终的派生类中会保存该间接共同基类数据成员的多份同名成员。前一个例如就是这种情况。C类intA::a;intA::a1;intB::a;intB::a2;inta;voidA:;display();voidB::display();voidshow();派生类C的数据成员派生类C的成员函数基类N的成员A新增成员基类N的成员B新增成员C新增成语NNABC5.6多重继承 在一个类中保存间接共同基类的多份同名成员,虽然有时是必要的,可以在不同的数据成员中存放不同的数据。但大多数情况下是不必要的,浪费较多内存空间,容易出错。实际上并不需要这么多份拷贝。 C++提供虚基类的技术来解决这仪问题。 其解决思路是,在继承间接共同基类时,内存里只存储一份成员。虚基类定义的一般形式 class派生类名:virtual继承方式基类名 即在声明派生类时,将关键字virtual加在继承方式前面。经过这样的声明后,当基类通过多条派生路径被一个派生类中只继承一次,即基类成员只保存一次。5.6多重继承 需要注意的是,为了保证虚 基类在派生类中只继承一次,应该 在该基类的所有直接派生类中声明 为虚基类。否那么仍然会出现对虚基 类的屡次继承。 如果象右图那样,只在A,B 中将N声明为虚基类,而C中没有 将N声明为虚基类,那么派生类D 中仍然有冗余的基类拷贝。类N类A类C类D类Bvirtualvirtual5.6多重继承虚基类的初始化:在最后的派生类中,不仅要初始化直接基类,而且还要初始化虚基类。 如果虚基类中定义了带参数的构造函数,而且没有定义默认构造函数,那么在所有直接派生和间接派生类中通过构造函数的初始化表对虚基类进行初始化。如: 注意,在定义多重继承的 派生类D时,由于虚基类在派生 类中只有一份数据成员,所以 这份数据成员的初始化必须由 最后的派生类直接给出,以防止 出现B、C的构造函数给出不同 的初始化参数而产生矛盾。classA{A(inti){}};classB:virtualpublicA{B(intn):A(n){}};classC:virtualpublicA{C(intn):A(n){}};classD:publicB,publicC{D(intn):A(n),B(n),C(n){}};5.6多重继承#include<iostream>#include<string>Usingnamespacestd;classperson{public:person(stringnam,chars,inta){name=nam;sex=s;age=a;}protected:stringname;charsex;intage;};classteacher:virtualpublicperson{public:teacher(stringnam,chars,inta,stringt):person(nam,s,a){title=t;}protected:stringtitle;};classstudent:virtualpublicperson{public:student(stringnam,chars,inta,floatsco):person(nam,s,a),score(sco){}protected:floatsco;};classgraduate:publicteacher,publicstudent{public:graduate(stringnam,chars,inta,stringt,floatsco,floatw):
person(nam,s,a),teacher(nam,s,a,t),student(nam,s,a,sco),wage(w){}voidshow(){cout<<“name:”<<name<<endl;cout<<“age:”<<age<<endl;cout<<“sex:”<<sex<<endl;cout<<“score:”<<score<<endl;cout<<“wages:”<<wage<<endl;}private:floatwage;};voidmain(){graduates1(“wan”,”m”,24,”assistant”,90.5,2000.50);s1.show();}5.7基类与派生类的转换 不同类型数据之间在一定条件下可以进行类型转换,如,整数赋给双精度数,但不能赋给指针变量。这种不同类型数据之间的自动转换和赋值,称为“赋值兼容”。 我们现在关心的是,基类和派生类之间是否也有赋值兼容的关系,能否进行类型间的转换? 答复是肯定的。基类与派生类之间有赋值兼容关系,由于派生类中包含从基类继承的成员,因此可以将派生类的值赋给基类对象,在用到基类对象的时候可以用其子类对象代替。我们分以下几种情况来讨论。5.7基类与派生类的转换派生类对象可以向基类对象赋值 可以用公用派生类对象对其基类对象赋值。如 Aa1;//定义基类A对象a1 Bb1;//定义A的公用派生类B的对象b1 a1=b1;//将派生类对象b1的值赋给基类A对象a1 这种情
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年高考政治专题复习为人民服务的政府提升练习题含解析
- 商业步行街休息区地砖安装合同
- 绿化工程翻新施工合同
- 知识产权合同管理办法范本
- 跨境电商孵化器租赁合同指南
- 云南省昭通市(2024年-2025年小学五年级语文)统编版专题练习(下学期)试卷及答案
- 餐饮场地暖施工服务合同
- 阑尾炎术前的用药护理
- 《谈判技巧与技术》课件
- 述职报告未来工作规划
- 第6章 智能网联汽车测评技术
- 单向板结构设计
- 《强化学习理论与应用》环境
- 普通高等学校学生转学申请表
- 房租、水、电费(专用)收据Excel模板
- 习近平总书记关于教育的重要论述研究学习通章节答案期末考试题库2023年
- 重症急性胰腺炎ppt恢复课件
- 2022江苏省沿海开发集团限公司招聘23人上岸笔试历年难、易错点考题附带参考答案与详解
- 乡镇卫生院6S管理内容和要求
- 数学教育概论 第3版
- 2023年中考英语写作高级替换词
评论
0/150
提交评论