南京邮电大学C++实验(二)继承与派生实验(仅参考)

(作者有话说:文章包含的代码运行结果可能与图片结果有所差异,请根据自己的需要进行修改)

实验名称:类和对象的定义及使用

一、实验目的和要求

(1)掌握单继承和多重继承下派生类的定义方法,理解基类成员在不同的继承方式下不同的访问属性。

(2)正确定义派生类的构造函数与析构函数,理解定义一个派生类对象时各个构造函数、析构函数被调用的顺序。

(3)正确定义虚基类,消除在多层次多重继承方式下顶层基类中成员访问的二义性问题,关注此时各构造函数、析构函数的调用顺序。

(4)通过基类与公有派生类的定义,及基类对象、指针、引用与派生类的对象、地址间相互赋值的方法,正确理解赋值兼容的4种情况,通过程序理解其不可逆性。

二、实验环境(实验设备)

硬件:  微型计算机

软件:  Windows 操作系统、Microsoft Visual Studio 2010

三、实验原理及内容

实验题目1: 定义一个车基类,派生出自行车类和汽车类,又以自行车类和汽车类为基类共同派生出摩托车类,每个类都要定义带有参数的构造函数。对自行车类继承车基类的方式分别用privateprotectedpublic,观察基类成员在派生类中的访问属性;观察自行车类、汽车类和摩托车类对象定义时构造、析构函数的调用顺序。最后将车基类定义为虚基类再观察程序运行结果。

实验解答:

根据提示进行填写完整实验指导204页代码对应位置内容如下:

( 1 )       MaxSpeed = m;                                                    

( 2 )       Weight = w;                                                    

( 3 )       Vehicle(m, w)                                                    

( 4 )       Height = h;                                                    

( 5 )       Vehicle::Show();                                                     

( 6 )       cout << "It\'s height is:" << Height << endl;                                                   

( 7 )       b(15, 75, 60);                                                    

此时程序的运行结果是:

将继承方式改为private或protected,观察并分析程序的编译结果。

继承方式改为protected:

  继承方式改为private:

在Bicycle类下面增加Car类的定义,参考实验教材给出的代码,划线部分自己完成。

( 8 )       Vehicle(m, w)                                                     

( 9 )       SeatNum = s;                                                     

( 10 )      Vehicle::Show();                                                     

( 11 )      cout << "It\'s SeatNum is:" << SeatNum << endl;                         

( 12 )      b(15, 75, 60);                                                     

( 13 )      c(120, 1500, 100);                                                      

增加的第3层类MotorCycle及修改以后的main( )函数,代码参见实验教材。

( 14 )      public Bicycle, public Car                                                     

( 15 )      mc(60, 240, 80, 2);                                                    

⑤ 将Vehicle声明为虚基类以消除二义性,具体要在上面的基础上修改3个地方。

·  将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 的初始化列表中增加对虚基类构造函数的调用。

( 16 )       Bicycle(m,w,h),Car(m,w,s),Vehicle(m,w)                                                   

实验题目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 :virtual 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 Bicycle…\n";
	}
	void Show()
	{
		Vehicle::Show();
		cout << "It\'s height is:" << Height << endl;
	}
};
class Car :virtual public Vehicle
{
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()
	{
		Vehicle::Show();
		cout << "It\'s SeatNum is:" << SeatNum << endl;
	}
};
class MotorCycle :public Bicycle, public Car
{
public:
	MotorCycle(int m, int w, int h, int s) :Bicycle(m,w,h),Car(m,w,s),Vehicle(m,w)
	{
		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()
{
	Bicycle b(15, 75, 60);
	b.Run();
	b.Stop();
	b.Show();
	Car c(120, 1500, 5);
	c.Run();
	c.Stop();
	c.Show();
	MotorCycle mc(60, 240, 80, 2);
	mc.Run();
	mc.Stop();
	mc.Show();
	return 0;
}

实验题目2定义Base类及它的公有派生类Derived类,两个类中均定义带参数的构造函数,基类中定义函数Show( ),派生类中也定义一个同名的Show( ),二者输出内容有所区别。主函数中定义基类的对象、指针、引用,也定义派生类的对象。

① 对赋值兼容的4种情况作测试,对每行的输出结果进行观察,理解赋值兼容何时调用基类的成员函数,什么情况下才会调用派生类的成员函数。

② 在主函数的return 0;语句前增加4条语句,观察并记下编译时的报错信息,理解赋值兼容的不可逆性。

实验解答:

①按提示将程序填写完整,代码参见实验教材,对应位置内容是:

(1 )        b1(2);                                                         

(2 )        d1(5);                                                        

(3 )        b1 = d1;                                                         

(4 )        & b2 = d1;                                                         

(5 )        * b3 = &d1;                                                         

(6 )        new Derived(6);                                                          

程序的运行结果是:

②  在主函数的return 0;语句前增加4条语句:

Derived d5=b1;

Derived &d6=b1;

Derived *d7=&b1;

d7=b3;

观察并记下编译时的报错信息,理解赋值兼容的不可逆性。

“初始化”: 无法从“Base”转换为“Derived” 

“初始化”: 无法从“Base”转换为“Derived &”

“初始化”: 无法从“Base *”转换为“Derived *”

“=”: 无法从“Base *”转换为“Derived *”

实验题目2代码:

#include<iostream>
using namespace std;
class Base
{
public:
	int i;
	Base(int x) :i(x)
	{
		cout << "Constructing base!" << endl;
	}
	void show()
	{
		cout << "i in Base is:" << i << endl;
	}
};
class Derived :public Base
{
public:
	Derived(int x) :Base(x)
	{
		cout << "Constructing derived!" << endl;
	}
	void show()
	{
		cout << "i in Derived is:" << i << endl;
	}
};
int main()
{
	Base b1(2);
	cout << "基类对象 b1.show( ):\n";
	b1.show();
	Derived d1(5);
	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(6);
	Base* b4 = d4;
	cout << "基类指针 b4 = d4,b4->show( ):\n";
	b4->show();
	cout << "派生类指针 d4, d4->show( ):\n";
	d4->show();
	delete d4;
	return 0;
}

四、实验小结(包括问题和解决方法、心得体会、意见与建议等)

(一)实验中遇到的主要问题及解决方法

1.在题目(1)中将Bicycle继承Vehicle类的方式分别修改为protected和private,再重新编译,请在小结中记录报错信息,解释原因。记录采取何种修改方式使程序正确运行?

报错信息:

“Vehicle::Run”不可访问,因为“Bicycle”使用“private”方式从“Vehicle”继承

“Vehicle::Stop”不可访问,因为“Bicycle”使用“private”方式从“Vehicle”继承

“Vehicle::Run”不可访问,因为“Bicycle”使用“protected”方式从“Vehicle”继承

“Vehicle::Stop”不可访问,因为“Bicycle”使用“protected”方式从“Vehicle”继承

原因:

采用“private”和“protected”继承,使得基类中可被继承的成员访问属性变为“private”或“protected”,而无法被访问

修改方式:

采取“public”继承方式可以使程序正确运行。

2. 在题目(2)中观察运行结果,总结在有赋值兼容的情况下,何时调用基类的成员函数,何时才会调用派生类的成员函数。

调用基类的成员函数:

(1)基类调用虚基类函数且对基类对象赋值

(2)调用非虚基类函数

调用派生类的成员函数:

调用虚基类函数且对基类的对象引用和基类的对象指针进行赋值

3.其它问题及解决方法:

问题:

定义派生类对象并生成新对象,忘记关键字new的用法,即给指针申请新空间

解决办法:

查找书籍,复习回顾new的用法

(二)实验心得

       通过本次实验,我了解的继承的三种方式的区别以及调用基类构造函数和基类其他成员函数的方法,同时理解了赋值兼容的4种情况。

(三)意见与建议(没有可省略)
  • 32
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
继承是面向对象编程中的一个重要概念,它实现了代码的重用和扩展性的增强。在继承中,一个子类可以继承一个或多个父类的属性和方法,并且可以在其基础上添加新的功能或修改原有的功能。 派生是指从已有类(父类)派生出新类(子类),并在新类中添加新的成员变量和成员方法。子类可以访问父类中的所有成员(除了私有成员),并且可以重写父类中的方法以满足自己的需求。 在继承中,子类可以继承父类中的属性和方法,但是如果子类中定义了与父类中同名的属性或方法,则子类中的定义会覆盖父类中的定义。此时,如果要访问父类中被覆盖的属性或方法,可以使用 super 关键字。 下面是一个简单的继承派生的示例: ```python class Person: def __init__(self, name, age): self.name = name self.age = age def print_info(self): print(f"Name: {self.name}, Age: {self.age}") class Student(Person): def __init__(self, name, age, grade): super().__init__(name, age) self.grade = grade def print_info(self): super().print_info() print(f"Grade: {self.grade}") person = Person("Tom", 20) person.print_info() # 输出:Name: Tom, Age: 20 student = Student("Jerry", 18, "Grade 12") student.print_info() # 输出:Name: Jerry, Age: 18, Grade: Grade 12 ``` 在上面的示例中,Person 类定义了一个构造方法和一个 print_info 方法,Student 类继承了 Person 类,并添加了一个 grade 属性和一个 print_info 方法。在 Student 类的构造方法中,使用 super() 函数调用父类的构造方法,以便初始化父类中的属性。 在 Student 类的 print_info 方法中,使用 super() 函数调用父类的 print_info 方法,以便输出父类中的信息。然后再输出子类中的信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鲤鱼Louis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值