第7章 继承性和派生类
- 格式:doc
- 大小:634.50 KB
- 文档页数:52
1、下列对基类和派生类关系的描述中,错误的是_________。
A)派生类是基类的具体化B)派生类是基类的子集C)派生类是基类定义的延续D)派生类是基类的组合2、继承具有_________ ,即当基类本身也是某一个类的派生类时,底层的派生类也会自动继承间接基类的成员。
A)规律性B)传递性C)重复性D)多样性3、下面_________的叙述不符合赋值兼容规则。
A)派生类的对象可以赋值给基类的对象B)基类的对象可以赋值给派生类的对象C)派生类的对象可以初始化基类的引用D)派生类的对象的地址可以赋值给指向基类的指针5、下面叙述错误的是_________。
A)派生类可以使用private派生B)对基类成员的访问必须是无二义性的C)基类成员的访问能力在派生类中维持不变D)赋值兼容规则也适用于多继承的组合6、下列说法中错误的是_________。
A)公有继承时基类中的public成员在派生类中仍是public的B)公有继承时基类中的private成员在派生类中仍是private的C)私有继承时基类中的public成员在派生类中是private的D)保护继承时基类中的public成员在派生类中是protected的7、C++的类有两种用法:一种是类的实例化,即生成类的对象,并参与系统的运行;另一种是通过_________派生出新的类。
A)复用B)继承C)封装D)引用8、下列关于虚基类的描述中,错误的是_________。
A)虚基类子对象的初始化由最派生类完成B)虚基类子对象的初始化次数与虚基类下面的派生类个数有关C)设置虚基类的目的是消除二义性D)带有虚基类的多层派生类构造函数的成员初始化列表中都要列出对虚基类构造函数的调用9、派生类的构造函数的成员初始化列表中,不能包含_________。
A)基类的构造函数B)派生类中子对象的初始化C)基类中子对象的初始化D)派生类中一般数据成员的初始化10、C++类体系中,不能被派生类继承的有_________。
第7章继承性和派生类本章内容:基类和派生类、单继承、多继承、虚基类。
类面向对象系统三要素对象继承封装性基础面向对象系统三特征继承性关键多态性补充继承是面向对象程序设计中软件重用的关键技术。
继承机制使用已经定义的类作为基础建立新的类定义,新的类是原有类的数据﹑操作和新类所增加的数据﹑操作的组合。
新的类把原有类作为基类引用,而不需要修改原有类的定义。
新定义的类作为派生类引用。
这种可扩充﹑可重用技术大大降低了大型软件的开发难度和维护费用。
7.1 基类和派生类我们称已存在的用来派生新类的类为基类,又称为父类。
由已存在的类派生出的新类称为派生类,又称为子类。
在C++语言中,一个派生类可以从一个基类派生,也可以从多个基类派生。
从一个基类派生的继承称为单继承;从多个基类派生的继承称为多继承。
单继承 多继承 7.1.1派生类的定义格式 单继承的定义格式:class 派生类名:继承方式 基类名 {派生类新定义成员 };public 表示公有继承 继承方式 private 表示私有继承protected 表示保护继承继承方式规定了如何访问从基类继承的成员。
继承方式却省,隐含私有继承。
多继承的定义格式如下:class 派生类名:继承方式1 基类名1,继承方式2 基类名2,…{派生类新定义成员};7.1.2 派生类的三种继承方式1.公有继承(public)公有成员是类的接口,在类中和类外可见。
特点:基类的公有和保护成员的访问属性在派生类中不变、而基类的私有成员不可访问。
基类成员派生类新定义成员成员派生类的对象可以访问基类中的公有成员;派生类的成员函数可以访问基类中的公有成员和保护成员。
2.私有继承(private)私有成员只能在类中可见,不能再类外或派生类中使用。
特点:基类中的公有成员和保护成员都以私有成员身份出现在派生类中,而基类的私有成员在派生类中不可访问。
基类成员派生类新定义成员成员派生类的成员函数可以访问基类中的公有成员和保护成员。
而无法再往下继承。
3.保护继承(protected)保护成员在类中和它的派生类中可见。
特点:基类的公有和保护成员都以保护成员的身份出现在派生类中,并且只能被它的派生类成员函数或友元函数访问,而基类的私有成员不可访问。
基类成员 派生类 新定义成员 成员派生类的成员函数可以访问基类中的公有成员和保护成员。
三种不同的继承方式的基类和派生类特性。
7.1.3 基类与派生类的关系在这个层次结构中,由上到下,是一个具体化、特殊化的过程;由下到上,是一个抽象化的过程。
最高层抽象程度最高,从上到下加入了自己的新特征,而最下层是最为具体的。
在派生过程中,派生出来的新类也同样可以作为基类再继续派生新的类。
直接参与派生出某类的基类称为直接基类。
基类的基类称为间接基类,比如A类派生出B类,B类又派生出C类。
则B类是C类的直接基类,A 类是B类的直接基类。
而A类可以称为C类的间接基类。
7.2 单继承7.2.1 成员访问权限的控制例7.1#include<iostream.h>class A{ public:void f1( );protected:int j1;private:int i1;};class B:public A{ public:void f2( );protected:int j2;private:int i2;};class C:public B{ public:void f3( );};问题: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中对象c3能否访问直接基类B中:f2( ), j2,i2?能否访问间接基类A中:f1( ),j1,i1?例 7.2#include<iostream.h>class A{ public:void f(int i){cout<<i<<endl;}void g( ){cout<<”g\n”;} };class B:A{ public:void h( ){cout<<”h\n”;}A::f;};void main( ){ B d1;d1.f(6);d1.g( );d1.h( );}问题:1.d1.g( );出现编译错。
2.去掉d1.g( );执行结果为:6h3. A::f;将基类中的公有成员说明成派生类的公有成员。
4.将私有继承改为公有继承输出为:6gh例 7.3#include<iostream.h>#include<string.h>class A{ public:A(const char *nm){ strcpy(name,nm);}private:char name[80];};class B:public A{ public:B(const char *nm):A(nm){ }void PrintName( ) const{ cout<<”name:”<<name<<endl;} };void main( ){ B b1(“wang li”);b1.PrintName( );}问题:1.cout<<”name:”<<name<<endl;编译错。
2.将类A中private改为protected。
3.输出为:name:wang li7.2.2派生类的构造和析构函数派生类继承了基类的成员,实现了原有代码的重用,这只是一部分,而代码的扩充才是最主要的,只有通过添加新的成员,加入新的功能,类的派生才有实际意义。
基类的构造函数和析构函数不能被继承。
在派生类中,如果对派生类新增的成员进行初始化,就必须由程序员针对实际需要加入新的构造函数。
与此同时,对所有从基类继承下来的成员的初始化工作,还是由基类的构造函数完成,我们必须在派生类中对基类的构造函数所需要的参数进行设置。
1.构造函数派生类构造函数的一般形式为:派生类名(派生类构造函数总叁数表):基类构造函数(参数表1),子对象名(参数表2){ 派生类中数据成员初始化}派生类构造函数执行的一般次序如下:1.基类构造函数。
2.子对象的构造函数。
3.派生类构造函数下面分别举例子说明各个不同的继承方式:例 7.4 公有继承#include<iostream.h>class Point //基类Point { public:Point(float xx=0,float yy=0){X=xx;Y=yy;}void Move(float x,float y){X+=x;Y+=y;}void print1( ){cout<<X<<”,”<<Y<<endl;}private:float X,Y;};class Rectangle: public Point //派生类{public: //新增公有成员Rectangle(float x,float y,float w,float h ) :Point(x,y){W=w;H=h;}void print2( ){cout<<W<<”,”<<H<<endl;}private: //新增私有数据成员float W,H;};void main( ){ Rectangle rect(2,3,20,10); //定义对象rect.Move(3,2); //移动点位置cout<<"The data of rect(X,Y,W,H):"<<endl; rect.print1( );//输出点参数rect.print2( );//输出矩形参数}输出:The data of rect(X,Y,W,H):5,520,10例 7.5 保护继承#include<iostream.h>class Point //基类Point { public:Point(float xx=0,float yy=0) {X=xx;Y=yy;} v oid Move(float x,float y) {X+=x;Y+=y;}void print1( ){cout<<X<<","<<Y<<endl;}private:float X,Y;};class Rectangle: protected Point //派生类{public: //新增公有成员Rectangle(float x,float y,float w,float h ) :Point(x,y){W=w;H=h;}Point::Move;Point::print1;void print2( ){cout<<W<<","<<H<<endl;}private: //新增私有数据成员f loat W,H;};void main(){ Rectangle rect(2,3,20,10); //定义对象rect.Move(3,2); //移动点位置cout<<"The data of rect(X,Y,W,H):"<<endl; rect.print1( );//输出点参数rect.print2( );//输出矩形参数}例7.6私有继承#include<iostream.h>class Point //基类{public:Point(float xx=0, float yy=0){X=xx;Y=yy;}void Move(float xOff, float yOff){X+=xOff;Y+=yOff;}void print( ){cout<<X<<","<<Y<<endl;}private:float X,Y;};class Rectangle: private Point //派生类{public: //新增公有成员Rectangle(float x, float y, float w, float h) :Point(x,y){W=w;H=h;}void Move(float xOff, float yOff){Point::Move(xOff,yOff);}void print( ){Point::print( );cout<<W<<","<<H<<endl;}private: //新增私有数据float W,H;};void main( ){ Rectangle rect(2,3,20,10); //定义对象rect.Move(3,2); //移动点位置cout<<"The data of rect(X,Y,W,H):"<<endl;rect.print( );}输出:The data of rect(X,Y,W,H):5,520,10和例7.4主函数最大的不同是:本例的Rectangle 类对象rect调用的函数都是派生类自身的公有成员,因为是私有继承,它不可能访问到任何一个基类的成员。