一、填空题
(1)如类果类A继承了B,那么类A被称为 基 类,而类B被称为 派生 类。
(2)C++的两种继承为: 单继承 和 多继承 。
(3)在默认情况下的继承方式为 私有继承方式 。
(4)从基类中公有派生一个类时,基类的公有成员就成为派生类的 公有 成员,而这个基类的保护成员就成为派生类的 保护 成员。
(5)C++提供了 多继承 机制,允许一个派生类可以继承多个基类,甚至这些基类是互不相关的。
(6)类X中的名字N 支配类Y中同名的名字N,是指类X以类Y为它的一个基类,这称为 支配规则 。
(7)引进虚基类的目的是 解决二义性 。
(8)在一个继承结构中,解决二义性的方法有 使用作用域运算符 和 引进虚基类 。
二、选择题(至少选一个,可以多选)
(1)C++语言建立类族是通过( B )。
A.类的嵌套 B.类的继承 C.虚函数 D.抽象类
(2) 继承是( CD )的方法。
A.将特殊的类变成通用的类
B.将通用的参数传送给特殊的类的对象
C.将通用的类变成特殊的类
D.将已有的类添加新的特性,但不重写它们
(3)继承的优点是( ABC )。
A.扩大类的使用范围,更便于使用类库
B.避免重写程序代码,提供有用的概念框架
C.把类转化成有条理的层次结构
D.通过继承的自然选择和重写使类进一步拓展
(4)下面叙述不正确的是( C )。
A.基类的保护成员在保护派生类中仍然是保护的
B.基类的保护成员在公有派生类中仍然是保护的
C.基类的保护成员在私有派生类中仍然是保护的
D.对基类的保护成员的访问必须是无二义性的
(5)派生类的对象对它的基类成员中( A )是可以访问的。
A.公有继承的公有成员
B.公有继承的私有成员
C.公有继承的保护成员
D.私有继承的公有成员
(6)( C )是可以访问类对象的私有数据成员的。
A.该类的对象 B.该类友元类派生的成员函数 C.类中的友元函数 D.公有派生类的成员函数
(7)多继承是( B )。
A.多个单继承的叠加
B.派生类有多个直接基类
C.多个派生类有唯一的基类
D.每个派生类最多只有一个直接基类,但它可以有多个间接基类
(8)关于多继承二义性的描述,( D )是错误的。
A.派生类的多个基类中存在同名成员时,派生类对这个成员访向可能出现二义性
B.由于二义性原因,一个类不能从同一个类中一次以上直接继承
C.使用作用域运算符对成员进行限制可以解决二义性
D.派生类和它的基类中出现同名函数时,派生类对这个成员函数的访问可能出现二义性
(9) 作用域运算符通常用来( AD )。
A.指定特定的类
B.指明从哪一个基类中导出来的
C.在某些成员函数中限定静态变量的可视范围
D.解决二义性
(10)多继承派生类析构函数释放对象时,( A )被最先调用。
A.派生类自己的析构函数
B.基类的析构函数
C.根基类的析构函数
D.派生类中子对象类的析构函数
三、判断题
(1)增加一个基类的派生类,需要对基类进行根本改变。(错)
(2)如果没有为派生类指定构造函数,则派生类的对象会调用基类的构造函数。(对)
(3)对一个类来说,可能的访问权限为: private.public.protected 和不可访问。(错)
(4)无论哪种派生方式,基类中的私有成员在派生类中都是不可访问的。(对)
(5)在派生过程中,派生类继承包括构造函数和析构函数在内的所有基类成员。(错)
(6) 在单继承中,派生类对象对基类成员函数的访问也可能出现二义性。(错)
四、筒答题
(1)在面向对象技术中,类与类之间的关系如何表示?
答:在面向对象技术中,类是数据和操作的集合,它们之间主要有3中关系:Has-A、Uses-A和Is-A。
Has-A表示类的包含关系,用以描述一个类由多个“部件类”构成。在面向对象技术中,实现Has-A关系用类成员表示,即第3章中已学的子对象。
Uses-A表示一个类部分地使用另一个类。在面向对象技术中,这种关系通过类之间成员函数的相互联系或对象参数传递实现。另外,通过定义友元也能实现这种关系。
Is-A表示一种分类方式,描述类的抽象和层次关系。
(2)简述赋值兼容规则。
答:所谓赋值兼容规则是指在公有继承情况下,一个派生类的对象可以作为基类的对象来使用。具体来说,就是下面3种情况:
①派生类的对象可以赋给基类的对象。
②派生类的对象可以初始化基类的引用。
③派生类的对象的地址可以赋给指向基类的指针。
(3)简述在 3 种继承方式下基类成员的访问权限。
答:当类的继承方式为公有继承时,在派生类中,基类的公有成员和保护成员被继承后分别作为派生类的公有成员和保护成员,这样使得派生类的成员函数可以直接访问它们,而派生类的成员函数无法直接访问基类的私有成员。 在类外部,派生类的对象可以访问继承下来的基类公有成员。
当类的继承方式为私有继承时,在派生类中,基类的公有成员和保护成员作为派生类的私有成员,派生类的成员函数可以直接访问它们,而派生类的成员函数无法直接访问基类的私有成员。在类外部,派生类的对象无法访问基类的所有成员。
当类的继承方式为保护继承时,在派生类中,基类的公有成员和保护成员作为派生类的保护成员,派生类的成员函数可以直接访问它们,而派生类的成员函数无法直接访问基类的私有成员。在类外部,派生类的对象无法基类的所有成员。
(4)简述在继承方式下创建派生类对象时,构造函数调用顺序,以及删除派生类对象时派生类析构函数的调用顺序。
答:创建派生类对象时构造函数调用顺序:首先调用基类构造函数,子对象所在类构造函数次之,最后执行派生类构造函数。
删除派生类对象时派生类析构函数的调用顺序:先调用派生类的析构函数;再调用派生类中子对象类的析构函数;再调用普通基类的析构函数;最后调用虚基类的析构函数。
(5) 简述派生类构造函数的规则。
答:第1种情况:若派生类有构造函数而基类没有,当创建派生类的对象时,派生类相应的构造函数会被自动调用。
第2种情况:若派生类没有构造函数而基类有,则基类必须拥有默认的构造函数。只有这样,当创建派生类的对象时,才能自动调用基类的默认构造函数。
第3种情况:若派生类有构造函数,且基类有默认构造函数,则创建派生类的对象时,基类的默认构造函数会自动调用,除非当前被调用的派生类构造函数在其初始化列表中显示调用了基类的有参构造函数。
第4种情况:若派生类和基类都有构造函数,但基类没有默认构造函数,则派生类的每一个构造函数必须在其初始化列表中显示调用基类的某个构造函数。只有这样,当创建派生类的对象时,基类的构造函数才能获得执行机会。
五、程序分析题(写出程序的输出结果)
输出结果如下:
分析:
定义一个点类(Point)、矩形类(Rectangle)和立方体类(Cube)的层次结构。矩形包括长度和宽度两个新数据成员,矩形的位置从点类继承,立方体类由长度、宽度和高度构成。要求各类提供支持初始化的构造函数和显示自己成员的成员函数。编写主函数,测试这个层次结构,输出立方体类的相关信息。
(1)如类果类A继承了B,那么类A被称为 基 类,而类B被称为 派生 类。
(2)C++的两种继承为: 单继承 和 多继承 。
(3)在默认情况下的继承方式为 私有继承方式 。
(4)从基类中公有派生一个类时,基类的公有成员就成为派生类的 公有 成员,而这个基类的保护成员就成为派生类的 保护 成员。
(5)C++提供了 多继承 机制,允许一个派生类可以继承多个基类,甚至这些基类是互不相关的。
(6)类X中的名字N 支配类Y中同名的名字N,是指类X以类Y为它的一个基类,这称为 支配规则 。
(7)引进虚基类的目的是 解决二义性 。
(8)在一个继承结构中,解决二义性的方法有 使用作用域运算符 和 引进虚基类 。
二、选择题(至少选一个,可以多选)
(1)C++语言建立类族是通过( B )。
A.类的嵌套 B.类的继承 C.虚函数 D.抽象类
(2) 继承是( CD )的方法。
A.将特殊的类变成通用的类
B.将通用的参数传送给特殊的类的对象
C.将通用的类变成特殊的类
D.将已有的类添加新的特性,但不重写它们
(3)继承的优点是( ABC )。
A.扩大类的使用范围,更便于使用类库
B.避免重写程序代码,提供有用的概念框架
C.把类转化成有条理的层次结构
D.通过继承的自然选择和重写使类进一步拓展
(4)下面叙述不正确的是( C )。
A.基类的保护成员在保护派生类中仍然是保护的
B.基类的保护成员在公有派生类中仍然是保护的
C.基类的保护成员在私有派生类中仍然是保护的
D.对基类的保护成员的访问必须是无二义性的
(5)派生类的对象对它的基类成员中( A )是可以访问的。
A.公有继承的公有成员
B.公有继承的私有成员
C.公有继承的保护成员
D.私有继承的公有成员
(6)( C )是可以访问类对象的私有数据成员的。
A.该类的对象 B.该类友元类派生的成员函数 C.类中的友元函数 D.公有派生类的成员函数
(7)多继承是( B )。
A.多个单继承的叠加
B.派生类有多个直接基类
C.多个派生类有唯一的基类
D.每个派生类最多只有一个直接基类,但它可以有多个间接基类
(8)关于多继承二义性的描述,( D )是错误的。
A.派生类的多个基类中存在同名成员时,派生类对这个成员访向可能出现二义性
B.由于二义性原因,一个类不能从同一个类中一次以上直接继承
C.使用作用域运算符对成员进行限制可以解决二义性
D.派生类和它的基类中出现同名函数时,派生类对这个成员函数的访问可能出现二义性
(9) 作用域运算符通常用来( AD )。
A.指定特定的类
B.指明从哪一个基类中导出来的
C.在某些成员函数中限定静态变量的可视范围
D.解决二义性
(10)多继承派生类析构函数释放对象时,( A )被最先调用。
A.派生类自己的析构函数
B.基类的析构函数
C.根基类的析构函数
D.派生类中子对象类的析构函数
三、判断题
(1)增加一个基类的派生类,需要对基类进行根本改变。(错)
(2)如果没有为派生类指定构造函数,则派生类的对象会调用基类的构造函数。(对)
(3)对一个类来说,可能的访问权限为: private.public.protected 和不可访问。(错)
(4)无论哪种派生方式,基类中的私有成员在派生类中都是不可访问的。(对)
(5)在派生过程中,派生类继承包括构造函数和析构函数在内的所有基类成员。(错)
(6) 在单继承中,派生类对象对基类成员函数的访问也可能出现二义性。(错)
四、筒答题
(1)在面向对象技术中,类与类之间的关系如何表示?
答:在面向对象技术中,类是数据和操作的集合,它们之间主要有3中关系:Has-A、Uses-A和Is-A。
Has-A表示类的包含关系,用以描述一个类由多个“部件类”构成。在面向对象技术中,实现Has-A关系用类成员表示,即第3章中已学的子对象。
Uses-A表示一个类部分地使用另一个类。在面向对象技术中,这种关系通过类之间成员函数的相互联系或对象参数传递实现。另外,通过定义友元也能实现这种关系。
Is-A表示一种分类方式,描述类的抽象和层次关系。
(2)简述赋值兼容规则。
答:所谓赋值兼容规则是指在公有继承情况下,一个派生类的对象可以作为基类的对象来使用。具体来说,就是下面3种情况:
①派生类的对象可以赋给基类的对象。
②派生类的对象可以初始化基类的引用。
③派生类的对象的地址可以赋给指向基类的指针。
(3)简述在 3 种继承方式下基类成员的访问权限。
答:当类的继承方式为公有继承时,在派生类中,基类的公有成员和保护成员被继承后分别作为派生类的公有成员和保护成员,这样使得派生类的成员函数可以直接访问它们,而派生类的成员函数无法直接访问基类的私有成员。 在类外部,派生类的对象可以访问继承下来的基类公有成员。
当类的继承方式为私有继承时,在派生类中,基类的公有成员和保护成员作为派生类的私有成员,派生类的成员函数可以直接访问它们,而派生类的成员函数无法直接访问基类的私有成员。在类外部,派生类的对象无法访问基类的所有成员。
当类的继承方式为保护继承时,在派生类中,基类的公有成员和保护成员作为派生类的保护成员,派生类的成员函数可以直接访问它们,而派生类的成员函数无法直接访问基类的私有成员。在类外部,派生类的对象无法基类的所有成员。
(4)简述在继承方式下创建派生类对象时,构造函数调用顺序,以及删除派生类对象时派生类析构函数的调用顺序。
答:创建派生类对象时构造函数调用顺序:首先调用基类构造函数,子对象所在类构造函数次之,最后执行派生类构造函数。
删除派生类对象时派生类析构函数的调用顺序:先调用派生类的析构函数;再调用派生类中子对象类的析构函数;再调用普通基类的析构函数;最后调用虚基类的析构函数。
(5) 简述派生类构造函数的规则。
答:第1种情况:若派生类有构造函数而基类没有,当创建派生类的对象时,派生类相应的构造函数会被自动调用。
第2种情况:若派生类没有构造函数而基类有,则基类必须拥有默认的构造函数。只有这样,当创建派生类的对象时,才能自动调用基类的默认构造函数。
第3种情况:若派生类有构造函数,且基类有默认构造函数,则创建派生类的对象时,基类的默认构造函数会自动调用,除非当前被调用的派生类构造函数在其初始化列表中显示调用了基类的有参构造函数。
第4种情况:若派生类和基类都有构造函数,但基类没有默认构造函数,则派生类的每一个构造函数必须在其初始化列表中显示调用基类的某个构造函数。只有这样,当创建派生类的对象时,基类的构造函数才能获得执行机会。
五、程序分析题(写出程序的输出结果)
- #include<iostream>
- using namespace std;
- class A
- {
- public:
- A(int i,int j){a=i;b=j;}
- void move(int x,int y){a+=x;b+=y;}
- void disp()
- {
- cout<<"("<<a<<","<<b<<")"<<endl;
- }
- private:
- int a,b;
- };
- class B:public A
- {
- public:
- B(int i,int j,int k,int l):A(i,j),x(k),y(l){}
- void disp()
- {
- cout<<x<<","<<y<<endl;
- }
- void fun1(){ move(13,15);}
- void fun2(){A::disp();}
- private:
- int x,y;
- };
- int main()
- {
- A aa(11,12);
- aa.disp();
- B bb(13,14,15,16);
- bb.fun1();
- bb.A::disp();
- bb.B::disp();
- bb.fun2();
- return 0;
- }
分析:
通过公有继承方式,从A类得到B类派生类B只有一个基类,所以是单继承。基类A定义了两个数据成员、两个成员函数。主函数中,调用A类的disp()输出第一行结果,fun1()调用的是A类的构造函数 move(int x,int y){a+=x;b+=y;},而move函数给出的初始值为{13,15},经过a=a+x,b=b+y后得到a=26,b=29.因此得到第二行结果,由于k=15,l=16,所以输出x(k),y(l),得到第三行结果。调用fun2()函数,由于A类中的a、b值已经变成了26、29,所以fun2()的结果就是第四行的运行结果。
六、程序设计题定义一个点类(Point)、矩形类(Rectangle)和立方体类(Cube)的层次结构。矩形包括长度和宽度两个新数据成员,矩形的位置从点类继承,立方体类由长度、宽度和高度构成。要求各类提供支持初始化的构造函数和显示自己成员的成员函数。编写主函数,测试这个层次结构,输出立方体类的相关信息。
程序如下:
- #include<iostream>
- using namespace std;
- class Point
- {
- protected:
- int x,y;
- public:
- Point(int myx,int myy){x=myx;y=myy;}
- void displayxy()
- {
- cout<<"The position of point:";
- cout<<"("<<x<<","<<y<<")"<<endl;
- }
- };
- class Rectangle:public Point
- {
- private:
- int l,w;
- public:
- Rectangle(int myx,int myy,int myl,int myw):Point(myx,myy)
- {l=myl;w=myw;}
- void displaylw()
- {
- cout<<"The length and width of rectangle:";
- cout<<l<<","<<w<<endl;
- }
- };
- class Cube:public Rectangle
- {
- private:
- int h;
- public:
- Cube(int myx,int myy,int myl,int myw,int myh):Rectangle(myx,myy,myl,myw)
- {h=myh;}
- void displayh()
- {
- cout<<"The height of cube:"<<h<<endl;
- }
- };
- int main()
- {
- Cube v(20,40,3,5,6);
- cout<<"The data of cube:"<<endl;
- v.displayxy();
- v.displaylw();
- v.displayh();
- return 0;
- }
运行结果如下: