实验四 继承与派生 一.实验目的及要求
1.掌握单继承和多重继承下派生类的定义方法,理解基类成员在不同的继承方式下不同的访问属性。
2.正确定义派生类的构造函数与析构函数,理解定义一个派生类对象时各个构造函数、析构函数被调用的顺序。
3.正确定义虚基类,消除在多层次继承方式下顶层基类中成员访问的二义性问题,关注此时各构造函数、析构函数的调用顺序。
4.通过基类与派生类的定义,及基类对象、指针、引用与派生类的对象、地址间相互赋值的方法,正确理解赋值兼容的4种情况,通过程序理解其不可逆性。 二.实验内容
在自己的文件夹下建立一个名为exp4的工程,在该工程中做如下操作: 定义一个车基类,派生出自行车类和汽车类,又以自行车类和汽车类为基类共同派生出摩托车类,每个类都要定义带有参数的构造函数。对自行车类继承基类的方式分别用private、protected、public,观察基类成员在派生类中的访问属性;观察自行车类、汽车类和摩托车类对象定义时构造、析构函数的调用顺序。最后将车基类定义为虚基类再观察程序运行结果,具体完成以下要求。
(1)定义基类Vehicle,具有两个保护成员变量:MaxSpeed、Weight,有3个公有的成员函数:Run()、Stop()、Show(),以及带参数构造函数、析构函数;再定义一个从Vehicle公有继承的Bicycle类,增加Height保护属性的成员变量,定义Bicycle类的构造函数、析构函数,改造Show函数,用于输出本类中的完整信息。main()函数中定义Bicycle类对象,观察构造函数和析构函数的执行顺序,以及各成员函数的调用。请用跟踪的方法观察程序运行的每一步究竟调用的是哪一个函数。
(2)在上一步基础上,将继承方式分别修改为protected和private,再重新编译,观察这时的报错信息并能解释。修改程序使程序正确运行。
(3)将Bicycle类的继承方式恢复为public,代码回到(1)的状态,再在Bicycle类下面增加一个第二层汽车类Car的定义,Car也是公有继承基类Vehicle,其中增加了一个保护成员变量SeatNum,表示汽车有几个座位,其定义方式与类Bicycle类似。主函数中定义该对象,观察运行结果。
(4)在上一步的基础上,再定义一个第三层类MotorCycle,该类以公有继承方式继承了第二层的Bicycle和Car类。定义其构造函数,要调用两个直接基类的构造函数,再改造函数Show(),输出所有四个成员变量的信息。主函数中只定义类MotorCycle的对象并调用相应的函数,代码请参考实验指导的(4)。程序进行编译,会产生4个错误、8个警告,因为存在二义性问题,请采用在同名成员前增加“基类名::”以消除二义性直到程序正确,观察运行结果。
(5)再将代码恢复至上一步未修改前,即存在4个错误、8个警告的状态,再作一定的修改,将Vehicle声明为虚基类以消除二义性,同时修改第三层的构造函数,其余代码不变,具体请参考实验指导的(5),观察运行结果,理解此时构造函数、析构函数的调用顺序及用虚基类消除二义性的原理。 三.试验程序及结果 1.
#include using namespace std;
{
public: A(){ cout
class B: public A {
public: B(){ cout
class C: public B {
public: C(){ cout
int main(void) { C obj; system("PAUSE"); return 0; }
2.
#include using namespace std;
{
protected: int a;
public: A(int x): a(x){ } void Show() const{ cout
class B {
protected: int b;
public: B(int x): b(x){ } void Show() const{ cout
class C: public A, public B {
public: C(int x, int y): A(x), B(y){ } void Show() const { cout
int main(void) { C obj(5, 18); obj.Show(); obj.A::Show(); obj.B::Show(); system("PAUSE"); return 0; }
3.
#include using namespace std;
class A {
private: int a; public:
// 公有函数: A(int x): a(x){ } void Show() const { cout
class B: public A {
protected: int b;
public: B(int x, int y): A(x), b(y){ } void Show() const { A::Show(); cout
int main(void) { B obj(5, 18); obj.Show(); system("PAUSE");
}
4.
#include using namespace std; class Base { private: int m; public: Base(int a): m(a){ } Base(const Base ©) { m = copy.m; } void Show() const { cout
} Derived obj(10, 18); obj.Show(); system("PAUSE"); return 0;
5.
#include using namespace std; /
class Person {
protected: char name[18]; int age; char sex[3]; public: Person(char nm[], int ag, char sx[]) { strcpy(name, nm); age = ag; strcpy(sex, sx); } void Show() const { cout
class Teacher: virtual public Person {
protected: char title[18]; public: Teacher(char nm[], int ag, char sx[], char tl[]): Person(nm, ag, sx)
{ strcpy(title, tl); } void Show() const { Person::Show(); cout
class Cadre: virtual public Person {
protected: char post[18]; public: Cadre(char nm[], int ag, char sx[], char pt[]): Person(nm, ag, sx { strcpy(post, pt); } void Show() const { Person::Show(); cout
class TeacherCadre: public Teacher, public Cadre {
protected: double wages; public: TeacherCadre(char nm[], int ag, char sx[], char tl[], char pt[], double wg) : Person(nm, ag, sx), Teacher(nm, ag, sx, tl), Cadre(nm, ag, sx, pt) { wages = wg; } void Show() const { Person::Show(); cout
int main(void) {
}
Teacher objTeacher("文冠杰", 48, "男", "教授"); Cadre objCadre("周杰", 56, "男", "院长"); TeacherCadre objTeacherCadre("李靖", 50, "女", "教授", "院长", 6890); objTeacher.Show(); objCadre.Show(); objTeacherCadre.Show();
system("PAUSE"); return 0;
6.
#include using namespace std;
class Staff {
protected: // 数据成员: int num; char name[18]; double rateOfAttend; double basicSal ; double prize ; static int count;
public: Staff(){ } void Input() { num = ++count; cout > name; cout > basicSal; cout > prize; cout > rateOfAttend; } void Output() const { cout
int Staff::count = 1000;
class Saleman : virtual public Staff {
protected: float deductRate; float personAmount;
public: Saleman (){ }; void Input( void ) { Staff::Input(); cout > personAmount;
cout > deductRate; } void Output() const { Staff::Output(); cout
class Manager: virtual public Staff {
protected: double totalDeductRate; double totalAmount;
public: Manager(){ } void Input( void ) { Staff::Input(); cout > totalAmount; cout > totalDeductRate; } void Output() const { Staff::Output(); cout
}
};
class SaleManager: public Saleman, public Manager
{
public:
SaleManager(){ };
void Input( void )
{
Staff::Input();
cout
cin >> personAmount;
cout
cin >> deductRate;
cout
cin >> totalAmount;
cout
cin >> totalDeductRate;
}
void Output() const
{
Staff::Output();
cout
cout
cout
cout
}
void OutputWage() const
{
cout
}
};
int main(void)
{
char flag = 'Y';
while (toupper(flag) == 'Y')
{
int n;
cin >> n;
if (n == 1)
{ // 员工
Staff objStaff;
objStaff.Input();
objStaff.Output();
objStaff.OutputWage();
}
else if (n == 2)
{ // 销售员
Saleman objSaleman;
objSaleman.Input();
objSaleman.Output();
objSaleman.OutputWage();
}
else if (n == 3)
{
Manager objManager;
objManager.Input();
objManager.Output();
objManager.OutputWage();
}
else if (n == 4)
{
SaleManager objSaleManager;
objSaleManager.Input();
objSaleManager.Output();
objSaleManager.OutputWage();
}
else
{ // 其它情况, 表示选择有误
cout
}
cout
cin >> flag;
}
system("PAUSE");
return 0;
}
五.实验总结
通过这次实验,我对类的继承和派生,派生类构造函数初始化基类成员和对象成员的方法,以及赋值兼容原则有了更深的理解
实验四 继承与派生 一.实验目的及要求
1.掌握单继承和多重继承下派生类的定义方法,理解基类成员在不同的继承方式下不同的访问属性。
2.正确定义派生类的构造函数与析构函数,理解定义一个派生类对象时各个构造函数、析构函数被调用的顺序。
3.正确定义虚基类,消除在多层次继承方式下顶层基类中成员访问的二义性问题,关注此时各构造函数、析构函数的调用顺序。
4.通过基类与派生类的定义,及基类对象、指针、引用与派生类的对象、地址间相互赋值的方法,正确理解赋值兼容的4种情况,通过程序理解其不可逆性。 二.实验内容
在自己的文件夹下建立一个名为exp4的工程,在该工程中做如下操作: 定义一个车基类,派生出自行车类和汽车类,又以自行车类和汽车类为基类共同派生出摩托车类,每个类都要定义带有参数的构造函数。对自行车类继承基类的方式分别用private、protected、public,观察基类成员在派生类中的访问属性;观察自行车类、汽车类和摩托车类对象定义时构造、析构函数的调用顺序。最后将车基类定义为虚基类再观察程序运行结果,具体完成以下要求。
(1)定义基类Vehicle,具有两个保护成员变量:MaxSpeed、Weight,有3个公有的成员函数:Run()、Stop()、Show(),以及带参数构造函数、析构函数;再定义一个从Vehicle公有继承的Bicycle类,增加Height保护属性的成员变量,定义Bicycle类的构造函数、析构函数,改造Show函数,用于输出本类中的完整信息。main()函数中定义Bicycle类对象,观察构造函数和析构函数的执行顺序,以及各成员函数的调用。请用跟踪的方法观察程序运行的每一步究竟调用的是哪一个函数。
(2)在上一步基础上,将继承方式分别修改为protected和private,再重新编译,观察这时的报错信息并能解释。修改程序使程序正确运行。
(3)将Bicycle类的继承方式恢复为public,代码回到(1)的状态,再在Bicycle类下面增加一个第二层汽车类Car的定义,Car也是公有继承基类Vehicle,其中增加了一个保护成员变量SeatNum,表示汽车有几个座位,其定义方式与类Bicycle类似。主函数中定义该对象,观察运行结果。
(4)在上一步的基础上,再定义一个第三层类MotorCycle,该类以公有继承方式继承了第二层的Bicycle和Car类。定义其构造函数,要调用两个直接基类的构造函数,再改造函数Show(),输出所有四个成员变量的信息。主函数中只定义类MotorCycle的对象并调用相应的函数,代码请参考实验指导的(4)。程序进行编译,会产生4个错误、8个警告,因为存在二义性问题,请采用在同名成员前增加“基类名::”以消除二义性直到程序正确,观察运行结果。
(5)再将代码恢复至上一步未修改前,即存在4个错误、8个警告的状态,再作一定的修改,将Vehicle声明为虚基类以消除二义性,同时修改第三层的构造函数,其余代码不变,具体请参考实验指导的(5),观察运行结果,理解此时构造函数、析构函数的调用顺序及用虚基类消除二义性的原理。 三.试验程序及结果 1.
#include using namespace std;
{
public: A(){ cout
class B: public A {
public: B(){ cout
class C: public B {
public: C(){ cout
int main(void) { C obj; system("PAUSE"); return 0; }
2.
#include using namespace std;
{
protected: int a;
public: A(int x): a(x){ } void Show() const{ cout
class B {
protected: int b;
public: B(int x): b(x){ } void Show() const{ cout
class C: public A, public B {
public: C(int x, int y): A(x), B(y){ } void Show() const { cout
int main(void) { C obj(5, 18); obj.Show(); obj.A::Show(); obj.B::Show(); system("PAUSE"); return 0; }
3.
#include using namespace std;
class A {
private: int a; public:
// 公有函数: A(int x): a(x){ } void Show() const { cout
class B: public A {
protected: int b;
public: B(int x, int y): A(x), b(y){ } void Show() const { A::Show(); cout
int main(void) { B obj(5, 18); obj.Show(); system("PAUSE");
}
4.
#include using namespace std; class Base { private: int m; public: Base(int a): m(a){ } Base(const Base ©) { m = copy.m; } void Show() const { cout
} Derived obj(10, 18); obj.Show(); system("PAUSE"); return 0;
5.
#include using namespace std; /
class Person {
protected: char name[18]; int age; char sex[3]; public: Person(char nm[], int ag, char sx[]) { strcpy(name, nm); age = ag; strcpy(sex, sx); } void Show() const { cout
class Teacher: virtual public Person {
protected: char title[18]; public: Teacher(char nm[], int ag, char sx[], char tl[]): Person(nm, ag, sx)
{ strcpy(title, tl); } void Show() const { Person::Show(); cout
class Cadre: virtual public Person {
protected: char post[18]; public: Cadre(char nm[], int ag, char sx[], char pt[]): Person(nm, ag, sx { strcpy(post, pt); } void Show() const { Person::Show(); cout
class TeacherCadre: public Teacher, public Cadre {
protected: double wages; public: TeacherCadre(char nm[], int ag, char sx[], char tl[], char pt[], double wg) : Person(nm, ag, sx), Teacher(nm, ag, sx, tl), Cadre(nm, ag, sx, pt) { wages = wg; } void Show() const { Person::Show(); cout
int main(void) {
}
Teacher objTeacher("文冠杰", 48, "男", "教授"); Cadre objCadre("周杰", 56, "男", "院长"); TeacherCadre objTeacherCadre("李靖", 50, "女", "教授", "院长", 6890); objTeacher.Show(); objCadre.Show(); objTeacherCadre.Show();
system("PAUSE"); return 0;
6.
#include using namespace std;
class Staff {
protected: // 数据成员: int num; char name[18]; double rateOfAttend; double basicSal ; double prize ; static int count;
public: Staff(){ } void Input() { num = ++count; cout > name; cout > basicSal; cout > prize; cout > rateOfAttend; } void Output() const { cout
int Staff::count = 1000;
class Saleman : virtual public Staff {
protected: float deductRate; float personAmount;
public: Saleman (){ }; void Input( void ) { Staff::Input(); cout > personAmount;
cout > deductRate; } void Output() const { Staff::Output(); cout
class Manager: virtual public Staff {
protected: double totalDeductRate; double totalAmount;
public: Manager(){ } void Input( void ) { Staff::Input(); cout > totalAmount; cout > totalDeductRate; } void Output() const { Staff::Output(); cout
}
};
class SaleManager: public Saleman, public Manager
{
public:
SaleManager(){ };
void Input( void )
{
Staff::Input();
cout
cin >> personAmount;
cout
cin >> deductRate;
cout
cin >> totalAmount;
cout
cin >> totalDeductRate;
}
void Output() const
{
Staff::Output();
cout
cout
cout
cout
}
void OutputWage() const
{
cout
}
};
int main(void)
{
char flag = 'Y';
while (toupper(flag) == 'Y')
{
int n;
cin >> n;
if (n == 1)
{ // 员工
Staff objStaff;
objStaff.Input();
objStaff.Output();
objStaff.OutputWage();
}
else if (n == 2)
{ // 销售员
Saleman objSaleman;
objSaleman.Input();
objSaleman.Output();
objSaleman.OutputWage();
}
else if (n == 3)
{
Manager objManager;
objManager.Input();
objManager.Output();
objManager.OutputWage();
}
else if (n == 4)
{
SaleManager objSaleManager;
objSaleManager.Input();
objSaleManager.Output();
objSaleManager.OutputWage();
}
else
{ // 其它情况, 表示选择有误
cout
}
cout
cin >> flag;
}
system("PAUSE");
return 0;
}
五.实验总结
通过这次实验,我对类的继承和派生,派生类构造函数初始化基类成员和对象成员的方法,以及赋值兼容原则有了更深的理解