当前位置:首页 >> 数学 >>

实验5(2) 参考答案


实验 5(2) 类的继承与派生 参考答案
一、实验目的与实验要求
(1) 掌握单继承和多重继承下派生类的定义方法, 理解基类成员在不同的继承方式下不 同的访问属性。 (2)正确定义派生类的构造函数与析构函数,理解定义一个派生类对象时构造函数、析 构函数的调用次序。 (3)理解同名冲突的产生原因,会使用虚基类来解决第三类同名冲突问题,并理解引入 虚基类后构造函数

、析构函数的调用顺序。 (4)理解赋值兼容的相关使用方法。

二、实验内容
题目 1:定义一个车基类,派生出自行车类和汽车类,并以自行车类和汽车类为基类共 同派生出摩托车类,每个类都要定义带有参数的构造函数。自行车类分别使用 private、 protected、public 三种方式来继承车基类,观察基类成员在派生类中的访问属性;观察自行 车类、汽车类和摩托车类对象定义时构造、析构函数的调用顺序。最后将车基类定义为虚基 类再观察程序运行结果。题目的具体要求如下。 ① 定义基类 Vehicle,它具有两个保护成员变量:MaxSpeed、Weight,有 3 个公有的成 员函数: Run( )、 Stop( )、 Show( ), 以及带参数的构造函数、 析构函数; 再定义一个从 Vehicle 公有继承的 Bicycle 类,增加保护属性的成员变量 Height,定义 Bicycle 类的构造函数、析 构函数,改造 Show 函数,用于输出本类中的完整信息。main( )函数中定义 Bicycle 类对象, 观察构造函数和析构函数的执行顺序, 以及各成员函数的调用。 使用跟踪的方法观察程序运 行的每一步究竟调用的是哪一个函数。 ② 在上一步基础上,将继承方式分别修改为 protected 和 private,再重新编译,观察这 时的报错信息并进行分析。 ③ 将 Bicycle 类的继承方式恢复为 public,代码回到 ① 的状态,再在 Bicycle 类下面 增加一个第二层汽车类 Car 的定义,Car 也是公有继承基类 Vehicle,其中增加了一个保护成 员变量 SeatNum,表示汽车有几个座位,其定义方式与类 Bicycle 类似。主函数中定义该类 对象,观察运行结果。 ④ 在上一步的基础上,再定义一个第三层类 MotorCycle,该类以公有方式继承了第二 层的 Bicycle 和 Car 类。定义其构造函数,要调用两个直接基类的构造函数,再改造函数 Show( ),输出所有四个成员变量的信息。主函数中只定义类 MotorCycle 的对象并调用相应 的函数,代码请参考实验指导 1 的④。程序进行编译,会产生 4 个错误、8 个警告,因为存 在二义性问题, 在同名成员前增加 “基类名:” : 以消除二义性直到程序正确, 观察运行结果。 ⑤ 再将代码恢复至上一步未修改前,即存在 4 个错误、8 个警告的状态,再作一定的 修改,将 Vehicle 声明为虚基类以消除二义性,同时修改第三层类的构造函数,其余代码不 变,具体请参考实验指导 1 的⑤。观察运行结果,理解此时构造函数、析构函数的调用顺序 及用虚基类消除二义性的原理。 参考程序如下:

#include <iostream> using namespace std; class Vehicle //定义基类 { protected: int MaxSpeed; //最大速度 int Weight; //重量 public: Vehicle(int m, int w) //初始化成员变量的值 { MaxSpeed=m; Weight=w; cout << "Constructing Vehicle...\n"; } ~Vehicle( ) { cout << "Destructing Vehicle...\n"; } void Run( ) { cout << "The vehicle is running!\n"; } void Stop( ) { cout << "Please stop running!\n"; } void Show( ) { cout << "It\'s maxspeed is:" << MaxSpeed << endl; cout << "It\'s weight is:" << Weight << endl; } }; class Bicycle: public Vehicle //定义派生类,公有继承 { protected: int Height; //高度,单位:厘米 public: Bicycle(int m, int w, int h):Vehicle(m,w) //调用基类构造函数 { Height=h; //为本类中新增成员提供初始值 cout << "Constructing Bicycle...\n"; } ~Bicycle( )

{ cout << "Destructing Bycycle...\n"; } void Show( ) //改造基类的 Show 函数 { Vehicle::Show();//调用基类 Show 输出 MaxSpeed 和 Weight 值 cout<<"It\'s Height is:"<<Height<<endl; //输出本类高度 } }; int main( ) { Bicycle b(120,2,4); //定义派生类对象 b.Run ( ); //观察构造、析构函数调用顺序 b.Stop( ); b.Show ( ); return 0; } 运行结果: Constructing Vehicle... Constructing Bicycle... The vehicle is running! Please stop running! It's maxspeed is:120 It's weight is:2 It's Height is:4 Destructing Bycycle... Destructing Vehicle... Press any key to continue ② 在上一步基础上,将继承方式分别修改为 protected 和 private,再重新编译,观察这 时的报错信息并进行分析。 答:继承方式是 private 或 protected 后,main 函数中的语句:b.Run ( ); b.Stop( );等均 不能通过编译,因为基类中的成员函数都是派生类的私有的或保护的成员函数,类外用派 生类对象都不能再调用。 ③ 将 Bicycle 类的继承方式恢复为 public,代码回到 ① 的状态,再在 Bicycle 类下面 增加一个第二层汽车类 Car 的定义,Car 也是公有继承基类 Vehicle,其中增加了一个保护成 员变量 SeatNum,表示汽车有几个座位,其定义方式与类 Bicycle 类似。主函数中定义该类 对象,观察运行结果。 指导: 在 Bicycle 类下面增加 Car 类的定义,参考以下代码,划线部分自己完成。
class Car: public Vehicle { public: int SeatNum; Car (int m, int w, int s) : { (8) //座位数 //调用基类构造函数 //定义派生类 Car,公有继承

(9) cout << "Constructing Car...\n"; } ~Car( ) { cout << "Destructing Car...\n"; } void Show( ) { (10) (11) } };

//为本类中新增成员提供初始值

//改造基类的 Show 函数 //调用基类 Show 输出 MaxSpeed 和 Weight 值 //输出本类座位数

在主函数增加 Car 类对象的定义并调用相应函数,主函数代码如下。
int main( ) { Bicycle b.Run( ); b.Stop( ); b.Show ( ); Car c.Run ( ); c.Stop( ); c.Show ( ); return 0; } 参考程序如下: (13) //定义汽车类对象 (12) //定义自行车类对象

class Car: public Vehicle //定义派生类 Car,公有继承 { protected: int SeatNum; //座位数 public: Car (int m, int w, int s) : Vehicle(m,w) //调用基类构造函数 { SeatNum=s; //为本类中新增成员提供初始值 cout << "Constructing Car...\n"; } ~Car( ) { cout << "Destructing Car...\n"; } void Show( ) //改造基类的 Show 函数 { Vehicle::Show(); //调用基类 Show 输出 MaxSpeed 和 Weight 值 cout<<"It\'s SeatNum is:"<<SeatNum<<endl; //输出本类座位数

} }; int main( ) { Bicycle b(50,2,400); //定义自行车类对象 b.Run( ); b.Stop( ); b.Show ( ); Car c(120,2000,5); //定义汽车类对象 c.Run ( ); c.Stop( ); c.Show ( ); return 0; } 运行结果为: Constructing Vehicle... Constructing Bicycle... The vehicle is running! Please stop running! It's maxspeed is:50 It's weight is:2 It's Height is:400 Constructing Vehicle... Constructing Car... The vehicle is running! Please stop running! It's maxspeed is:120 It's weight is:2000 It's SeatNum is:5 Destructing Car... Destructing Vehicle... Destructing Bycycle... Destructing Vehicle... Press any key to continue ④ 在上一步的基础上,再定义一个第三层类 MotorCycle,该类以公有方式继承了第二 层的 Bicycle 和 Car 类。定义其构造函数,要调用两个直接基类的构造函数,再改造函数 Show( ),输出所有四个成员变量的信息。主函数中只定义类 MotorCycle 的对象并调用相应 的函数,代码请参考实验指导 1 的④。程序进行编译,会产生 4 个错误、8 个警告,因为存 在二义性问题, 在同名成员前增加 “基类名:” : 以消除二义性直到程序正确, 观察运行结果。 指导:增加的第 3 层类 MotorCycle 及修改以后的 main( )函数。
class MotorCycle: public Bicycle, public Car { public: MotorCycle(int m, int w, int h, int s): (14) //调用两基类构造函数 //第 3 层类,从第 2 层两个类公有继承

{ cout << "Constructing MotorCycle...\n"; } ~MotorCycle( ) { cout << "Destructing MotorCycle...\n"; } void Show( ) { cout << "It\'s maxspeed is:" << MaxSpeed << endl; //错误 cout << "It\'s weight is:" << Weight << endl; cout << "It\'s height is:" << Height << endl; cout << "It\'s seatnum is:" << SeatNum << endl; } }; int main( ) { MotorCycle mc.Run ( ); mc.Stop( ); mc.Show ( ); return 0; } (15) //定义摩托车类对象 //错误 //错误 //错误 //输出 4 个成员变量的信息, 需消除二义性

程序为: class MotorCycle: public Bicycle, public Car //第 3 层类,从第 2 层两个类公有继承 { public: MotorCycle(int m, int w, int h, int s): Bicycle(m,w,h),Car(m,w,s) //调用两基类构造函数 { cout << "Constructing MotorCycle...\n"; } ~MotorCycle( ) { cout << "Destructing MotorCycle...\n"; } void Show( ) //输出 4 个成员变量的信息,需消除二义性 { cout << "It\'s maxspeed is:" << MaxSpeed << endl; //错误 cout << "It\'s weight is:" << Weight << endl; //错误 cout << "It\'s height is:" << Height << endl; cout << "It\'s seatnum is:" << SeatNum << endl; }

}; int main( ) { MotorCycle mc(120,1000,2,2); //定义摩托车类对象 mc.Run ( ); //错误 mc.Stop( ); //错误 mc.Show ( ); return 0; } 编译出错: E:\2012-2013(2)\C++教学\教案\Text1.cpp(113) : error C2385: 'MotorCycle::MaxSpeed' is ambiguous E:\2012-2013(2)\C++ 教 学 \ 教 案 \Text1.cpp(113) : warning C4385: could be the 'MaxSpeed' in base 'Vehicle' of base 'Bicycle' of class 'MotorCycle' E:\2012-2013(2)\C++教学\教案\Text1.cpp(113) : warning C4385: or the 'MaxSpeed' in base 'Vehicle' of base 'Car' of class 'MotorCycle' E:\2012-2013(2)\C++教学\教案\Text1.cpp(114) : error C2385: 'MotorCycle::Weight' is ambiguous E:\2012-2013(2)\C++教学\教案\Text1.cpp(114) : warning C4385: could be the 'Weight' in base 'Vehicle' of base 'Bicycle' of class 'MotorCycle' E:\2012-2013(2)\C++教学\教案\Text1.cpp(114) : warning C4385: or the 'Weight' in base 'Vehicle' of base 'Car' of class 'MotorCycle' E:\2012-2013(2)\C++教学\教案\Text1.cpp(125) : error C2385: 'MotorCycle::Run' is ambiguous E:\2012-2013(2)\C++教学\教案\Text1.cpp(125) : warning C4385: could be the 'Run' in base 'Vehicle' of base 'Bicycle' of class 'MotorCycle' E:\2012-2013(2)\C++教学\教案\Text1.cpp(125) : warning C4385: or the 'Run' in base 'Vehicle' of base 'Car' of class 'MotorCycle' E:\2012-2013(2)\C++教学\教案\Text1.cpp(126) : error C2385: 'MotorCycle::Stop' is ambiguous E:\2012-2013(2)\C++教学\教案\Text1.cpp(126) : warning C4385: could be the 'Stop' in base 'Vehicle' of base 'Bicycle' of class 'MotorCycle' E:\2012-2013(2)\C++教学\教案\Text1.cpp(126) : warning C4385: or the 'Stop' in base 'Vehicle' of base 'Car' of class 'MotorCycle' 执行 cl.exe 时出错. 即输出 MaxSpeed、Weigh 和调用函数 Run()和 Stop()函数时出现二义性问题。 修改程序中主要是为数据成员和成员函数限定其所属类即可。 程序为: class MotorCycle: public Bicycle, public Car //第 3 层类,从第 2 层两个类公有继承 { public: MotorCycle(int m, int w, int h, int s): Bicycle(m,w,h),Car(m,w,s) //调用两基类构造函数 {

cout << "Constructing MotorCycle...\n"; } ~MotorCycle( ) { cout << "Destructing MotorCycle...\n"; } void Show( ) //输出 4 个成员变量的信息,需消除二义性 { cout << "It\'s maxspeed is:" << Bicycle::MaxSpeed << endl; //修改后 cout << "It\'s weight is:" << Car::Weight << endl; //修改后 cout << "It\'s height is:" << Height << endl; cout << "It\'s seatnum is:" << SeatNum << endl; } }; int main( ) { MotorCycle mc(120,1000,2,2); //定义摩托车类对象 mc.Bicycle::Run ( ); //修改后 mc.Bicycle::Stop( ); //修改后 mc.Show ( ); return 0; } 运行结果: Constructing Vehicle... Constructing Bicycle... Constructing Vehicle... Constructing Car... Constructing MotorCycle... The vehicle is running! Please stop running! It's maxspeed is:120 It's weight is:1000 It's height is:2 It's seatnum is:2 Destructing MotorCycle... Destructing Car... Destructing Vehicle... Destructing Bycycle... Destructing Vehicle... Press any key to continue ⑤ 再将代码恢复至上一步未修改前,即存在 4 个错误、8 个警告的状态,再作一定的 修改,将 Vehicle 声明为虚基类以消除二义性,同时修改第三层类的构造函数,其余代码不 变,具体请参考实验指导 1 的⑤。观察运行结果,理解此时构造函数、析构函数的调用顺序 及用虚基类消除二义性的原理。

指导:将 Vehicle 声明为虚基类以消除二义性,具体要在上面的基础上修改以下地方。 ? 将 class Bicycle: public Vehicle 修改为 class Bicycle: virtual public Vehicle。 ? 将 class Car: public Vehicle 修改为 class Car: virtual public Vehicle。 ? 在第 3 层类的构造函数 MotorCycle(int m,int w,int h,int s): (16) 的初始化列 表中增加对虚基类构造函数的调用。 ? 原来注释出错的地方将类名的限制去掉,恢复原样。如: cout << "It\'s maxspeed is:" << Bicycle::MaxSpeed << endl; //错误 恢复为:cout << "It\'s maxspeed is:" << MaxSpeed << endl; 按题意,将 Vehicle 声明为虚基类以消除二义性,具体修改; ? 将 class Bicycle: public Vehicle 修改为 class Bicycle: virtual public Vehicle。 ? 将 class Car: public Vehicle 修改为 class Car: virtual public Vehicle。 程序修改为: class MotorCycle: public Bicycle, public Car //第 3 层类,从第 2 层两个类公有继承 { public: MotorCycle(int m, int w, int h, int s): Vehicle(m,w),Bicycle(m,w,h),Car(m,w,s)// 调用两基类构造函数 { cout << "Constructing MotorCycle...\n"; } ~MotorCycle( ) { cout << "Destructing MotorCycle...\n"; } void Show( ) //输出 4 个成员变量的信息,需消除二义性 { cout << "It\'s maxspeed is:" << MaxSpeed << endl; //正确 cout << "It\'s weight is:" << Weight << endl; //正确 cout << "It\'s height is:" << Height << endl; cout << "It\'s seatnum is:" << SeatNum << endl; } }; int main( ) { MotorCycle mc(120,1000,2,2); //定义摩托车类对象 mc.Run ( ); //正确 mc.Stop( ); //正确 mc.Show ( ); return 0; } 运行结果为: Constructing Vehicle... Constructing Bicycle...

Constructing Car... Constructing MotorCycle... The vehicle is running! Please stop running! It's maxspeed is:120 It's weight is:1000 It's height is:2 It's seatnum is:2 Destructing MotorCycle... Destructing Car... Destructing Bycycle... Destructing Vehicle... Press any key to continue 题目 2: 定义 Base 类及它的公有派生类 Derived 类, 两个类中均定义带参数的构造函数, 基类中定义函数 Show( ),派生类中也定义一个同名的 Show( ),二者输出内容有所区别。主 函数中定义基类的对象、指针、引用,也定义派生类的对象。 (① 中 6 个空各 0.3 分,②分 析 0.2 分) ① 对赋值兼容的 4 种情况作测试,对每行的输出结果进行观察,理解赋值兼容何时调 用基类的成员函数,什么情况下才会调用派生类的成员函数。 ② 在主函数的 return 0;语句前增加 4 条语句,观察并记下编译时的报错信息,理解赋 值兼容的不可逆性。 程序如下: #include <iostream> using namespace std; class Base { public: int i; Base(int x): i(x) { } void show( ) { cout << "i in Base is: " << i << endl; } }; class Derived: public Base { public: Derived(int x): Base(x) { } void show( ) { cout << "i in Derived is: " << i << endl;

} }; int main( ) { Base b1(1); //定义基类对象 b1 cout << "基类对象 b1.show( ):\n"; b1.show( ); Derived d1(2); //定义派生类对象 d1 b1=d1; //用派生类对象给基类对象赋值 cout << "基类 b1=d1, b1.show( ):\n"; b1.show( ); cout << "派生类对象 d1.show( ):\n"; d1.show( ); Base & b2=d1; //用派生类对象来初始化基类引用 cout << "引用 b2=d1, b2.show( ):\n"; b2.show( ); Base * b3=&d1; //派生类对象的地址赋给指向基类的指针 cout << "基类指针 b3=&d1, b3->show( ):\n"; b3->show( ); Derived *d4=new Derived(3); //定义派生类指针并生成新对象 Base *b4 = d4 ; //派生类指针赋给指向基类的指针 cout << "基类指针 b4 = d4, b4->show( ):\n"; b4->show( ); cout << "派生类指针 d4, d4->show( ):\n"; d4->show( ); delete d4; return 0; } 运行结果: 基类对象 b1.show( ): i in Base is: 1 基类 b1=d1, b1.show( ): i in Base is: 2 派生类对象 d1.show( ): i in Derived is: 2 引用 b2=d1, b2.show( ): i in Base is: 2 基类指针 b3=&d1, b3->show( ): i in Base is: 2 基类指针 b4 = d4, b4->show( ): i in Base is: 3 派生类指针 d4, d4->show( ): i in Derived is: 3

Press any key to continue ① 对赋值兼容的 4 种情况作测试,对每行的输出结果进行观察,理解赋值兼容何时 调用基类的成员函数,什么情况下才会调用派生类的成员函数。 答:4 种情况: 基类对象 = 公有派生类对象 b1=d1; b1.show( );调用的是基类 Base 的成员函数 show; 指向基类对象的指针 = 公有派生类对象的地址 Base * b3=&d1; b3->show( ); 调用的是基类 Base 的成员函数 show; 指向基类对象的指针 = 指向公有派生类对象的指针 Base *b4 = d4 ; b4->show( ); 调用的是基类 Base 的成员函数 show; 基类的引用 = 公有派生类对象,即派生类对象可以初始化基类的引用。 Base & b2=d1; b2.show( ); 调用的是基类 Base 的成员函数 show; 由此可知,只要是基类的对象或对象指针(引用)均调用的是基类的函数;只有在调用 函 数 的 对 象 或 指 针 是 派 生 类 的 时 候 才 会 调 用 派 生 类 的 成 员 函 数 。 如 d1.show( ); d4->show( ); 均调用的是派生类的成员函数。 ② 在主函数的 return 0;语句前增加 4 条语句,观察并记下编译时的报错信息,理解赋 值兼容的不可逆性。 //增加 4 条语句,理解赋值兼容规则的不可逆性 Derived d5 = b1; 该语句编译不能通过,因为不能用基类对象对派生类对象初始化 Derived &d6 = b1; 该语句编译不能通过,因为派生类对象不能用来作为基类对象的别名 Derived *d7 = &b1; 该语句编译不能通过,因为派生类对象指针不能指向基类对象 d7 = b3; 该语句编译不能通过,因为派生类对象指针不能被赋值为基类对象指针 题目 2 指导: ① //赋值兼容原则
#include <iostream> using namespace std; class Base { public: int i; Base(int x): i(x) { }

void show( ) { cout << "i in Base is: " << i << endl; }

}; class Derived: public Base { public: Derived(int x): Base(x) { }

void show( ) { cout << "i in Derived is: " << i << endl; } };

int {

main( ) (1)

Base

//定义基类对象 b1

cout << "基类对象 b1.show( ):\n"; b1.show( ); Derived (3) cout << "基类 b1=d1, b1.show( ):\n"; b1.show( ); cout << "派生类对象 d1.show( ):\n"; d1.show( ); Base (4) //用派生类对象来初始化基类引用 (2) //定义派生类对象 d1 //用派生类对象给基类对象赋值

cout << "引用 b2=d1, b2.show( ):\n"; b2.show( ); Base (5) //派生类对象的地址赋给指向基类的指针

cout << "基类指针 b3=&d1, b3->show( ):\n"; b3->show( ); Derived *d4 = (6) //定义派生类指针并生成新对象 //派生类指针赋给指向基类的指针

Base *b4 = d4 ; cout << "基类指针 b4 = d4, b4->show( ):\n"; b4->show( );

cout << "派生类指针 d4, d4->show( ):\n"; d4->show( delete d4; return 0; } );

② //增加 4 条语句,理解赋值兼容规则的不可逆性
Derived d5 = b1; Derived &d6 = b1; Derived *d7 = &b1; d7 = b3;


相关文章:
实验答案(四-五-六)参考答案
实验答案(四-五-六)参考答案_工学_高等教育_教育专区。实验四 简单查询和连接...cname='离散数学')); (2) 查询 0101 课程的成绩高于张林的学生学号和成绩。...
05实验五参考答案
05实验五参考答案_其它_高等教育_教育专区。江西财经大学精品课程《数据库应用》...用子查询完成以下实验: (1) 查询未归还图书的读者编号、姓名和性别。 (2) ...
实验五答案
matlab实验题目 答案 积分 int trapz 微分 导数 矩阵输入 输出 行变换...1. clear;clc a=[2 1 -1 1;3 -2 1 -3;1 4 -3 5]; b=[1;4;...
实验5 循环结构程序设计(参考答案)
实验五 循环结构程序设计(参考答案) [实验任务一]:程序跟踪调试实例 5-1:error5_1.c 参考答案 程序跟踪调试实例 5-2:error5_2.c 参考答案 程序跟踪调试实例...
实验5(1) 参考答案
实验5(1) 参考答案_语文_高中教育_教育专区。实验 5(1) 类的组合 参考答案一、实验目的与实验要求(1)理解类组合的概念与作用。 (2)掌握对象成员的定义方法,...
面向对象实验(实验一~五参考答案)
2页 免费如要投诉违规内容,请到百度文库投诉中心;如要提出功能问题或意见建议,请点击此处进行反馈。 面向对象实验(实验一~五参考答案) 隐藏>> 南昌航空大学实验报...
答案_实验五 存储管理(二)
答案_实验五 存储管理(二) 隐藏>> 实验五 存储管理(二)学号: 实验目的: 1. 了解虚拟存储器。 2. 掌握分页存储管理的原理,熟悉段式存储和段页式存储管理。 3...
05实验五 符号计算实验(附答案)
05实验五 符号计算实验(附答案)_计算机软件及应用_IT/计算机_专业资料。实验五一、实验目的: 1、 掌握定义符号对象的方法 符号计算实验 2、掌握符号表达式的运算法...
实验五:程序设计(一)及其答案
实验五:程序设计(一)及其答案 隐藏>> 实验五:程序设计(一)一、实验目的 1.掌握输入输出语句的使用。 2.掌握利用if语句实现选择结构的方法。 3.掌握利用for语句...
上机实验五_答案(请自行校对)
上机实验五_答案(请自行校对)_理学_高等教育_教育专区。上机实验五学号: 循环...用于交换 a 和 b 的值 printf("请输入正整数 n(n>2) :"); scanf("%d...
更多相关标签: