【目的】

1. 进一步掌握类的派生与继承的概念、应用方法

2. 掌握继承方式对成员访问权限的影响

3. 掌握虚基类的用法


第三部分 实践项目

【项目1】理解基类中成员的访问限定符和派生类的继承方式

由下面派生类StudentB对基类StudentA的继承……

#include <iostream>
using namespace std;
class StudentA //(1)修改studentA类中各数据成员和成员函数的访问限定符,并观察发生的现象
{
public:
StudentA(int n,string nam,char s);
void showA();
~StudentA( ) { }
protected:
int num;
string name;
char sex ;
};


class StudentB: public StudentA //(2)修改此处的继承方式,并观察发生的现象
{
public:
StudentB(int n,string nam,char s,int a,string ad);
void showB( );
~StudentB( ) { }
private:
int age;
string addr;
};


StudentA::StudentA(int n,string nam,char s)
{
num=n;
name=nam;
sex=s;
}
void StudentA::showA()
{
cout<<"num: "<<num<<endl;
cout<<"name: "<<name<<endl;
cout<<"sex: "<<sex<<endl<<endl;
}


StudentB::StudentB(int n,string nam,char s,int a,string ad):StudentA(n,nam,s)
{
age=a;
addr=ad;
}
void StudentB::showB( )
{
cout<<"num: "<<num<<endl;
cout<<"name: "<<name<<endl;
cout<<"sex: "<<sex<<endl;
cout<<"age: "<<age<<endl;
cout<<"address: "<<addr<<endl<<endl;
}


int main( ) //(3)思考由于访问限定符和继承方式的改变,会引发什么现象的发生,并作出解释
{
StudentB stud1(10010,"Wang-li",'f',19,"115 Beijing Road,Shanghai");
StudentB stud2(10011,"Zhang-fun",'m',21,"213 Shanghai Road,Beijing");
StudentA stud3(20010,"He-xin",'m');
stud1.showB( );
stud2.showA( );
stud3.showA( );
return 0;
}


(1)尝试改变并运行


  请修改基类中成员的访问限定符和派生类的继承方式,考虑可能的运行结果或可能出现的错误,并在上机时进行验证、对比,达到理解派生类成员的访问属性的目的。


(2)总结


  记录(1)的结果,将出现的错误摘录下来,并加上自己的解释;用自己的话总结确定派生类成员的访问属性的原则,也写到报告博文中。




【项目2】(第11章习题9)分别定义Teacher(教师)类和Cadre(干部)类,采用多重继承方式由这两个类派生出新类Teacher_Cadre(教师兼干部)。要求: 


(1)在两个基类中都包含姓名、年龄、性别、地址、电话等数据成员。 


(2)在Teacher类中还包含数据成员title(职称),在Cadre类中还包含数据成员post(职务),在Teacher_Cadre类中还包含数据成员wages(工资)。 


(3)对两个基类中的姓名、年龄、性别、地址、电话等数据成员用相同的名字,在引用这些数据成员时,指定作用域。 


(4)在类体中声明成员函数,在类外定义成员函数。 


(5)在派生类Teacher_Cadre的成员函数show中调用Teacher类中的display函数,输出姓名、年龄、性别、职称、地址、电话,然后再用cout语句输出职务与工资。




【项目3】在下面一段类的定义中,自行车类的虚基类为车辆类,机动车类的虚基类也为车辆类,摩托车类的基类为自行车类和机动车类,类之间均为公有继承。


(1)根据上面各类间关系的描述,补全下面程序段中空缺的代码


(2)实现程序中声明的成员函数,注意相应操作中的动作发生的条件不能满足时应给出提示。


(3)运行程序,享受开摩托的过程。(请下载

​资源中​​一个可执行文件,可以先运行再编程。不必申请驾照,这个摩托车很安全。)


(4)在报告中回答问题:本题中使用虚基类的好处是什么?


#include <iostream>
#include<conio.h>
#include <windows.h>
using namespace std;
enum vehicleStaus {rest, running}; //车辆状态:泊车、行进
class vehicle //车辆类
{
protected:
int maxSpeed; //最大车速
int currentSpeed; //当前速度
int weight; //车重
vehicleStaus status; //rest-泊车状态;running-行进状态
public:
vehicle(int maxS, int w); //构造函数,初始时,当前速度总为0且处在停车状态
void start(); //由rest状态到running, 初速为1
void stop(); //由running状态到rest, 当前速度小于5时,才允许停车
void speed_up(); //加速,调用1次,速度加1
void slow_down(); //减速,调用1次,速度减1,速度为0时,停车
};


class bicycle :_____(1)_________//(1)自行车类的虚基类为车辆类
{
protected:
double height; //车高
public:
bicycle(int maxS=10, int w=50, int h=0.7); //定义构造函数
};


class motorcar : ______(2)__________//(2)机动车类的虚基类也为车辆类
{
protected:
int seatNum; //座位数
int passengerNum; //乘客人数
public:
motorcar(int maxS=150, int w=1500, int s=5, int p=1); //定义构造函数
void addPassenger(int p=1); //增加搭载的乘客,超员要拒载,有人下车时,p为负数。当然车上乘客至少有1个(司机)。只有车停稳后才能上下客。
};


class motorcycle: ______(3)_________ //(3)摩托车类的基类为自行车类和机动车类
{
public:
//定义构造函数
motorcycle(int maxS=90, int w=100, int s=3, int p=1, int h=0.7);
void show(); //显示摩托车的运行状态
};


int main( )
{
motorcycle m;
bool end=false;
while (!end){
cout<<"请操作:1-启动 2-加速 3-减速 4-有人上车 5-有人下车 6-停车 0-结束"<<endl;
char keydown= _getch(); //_getch()返回键盘上读取的字符
switch(keydown)
{
case '1':
cout<<"操作(启动)\t"; m.start(); break;
case '2':
cout<<"操作(加速)\t"; m.speed_up(); break;
case '3':
cout<<"操作(减速)\t"; m.slow_down(); break;
case '4':
cout<<"操作(有人上车)\t"; m.addPassenger(); break;
case '5':
cout<<"操作(有人下车)\t"; m.addPassenger(-1); break;
case '6':
cout<<"操作(停车)\t"; m.stop(); break;
case '0':
end=true; break;
}
m.show();
cout<<endl;
Sleep(200); //要包含头文件<windows.h>
}
return 0;
}


【项目4】日期时间类


  定义一个日期类Date,数据成员包括年、月、日,SetDate(int y,int m,int d)和PrintDate()函数分别用于设置日期和显示日期;再定义一个时间类Time,数据成员包括时、分、秒,SetTime(int h,int m,int s)和PrintTime()函数分别用于设置时间和显示时间,在此基础上再定义一个日期时间类TimeDate,充分利用已有的两个类,并编写主函数测试所定义的类结构。




【项目5(选做)】类的组合与继承


(1)先建立一个Point(点)类,包含数据成员x,y(坐标点);


(2)以Point为基类,派生出一个Circle(圆)类,增加数据成员(半径),基类的成员表示圆心;


(3)编写上述两类中的构造、析构函数及必要的输入输出函数


(4)定义友元函数int locate,判断点p在圆c上、圆c内或圆c外,返回值<0圆内,==0圆上,>0 圆外;


(5)重载关系运算符(6种)运算符,使之能够按圆的面积比较两个圆的大小;


(6)给定一点p,求出该点与圆心相连成的直线与圆的两个交点并输出


下面给出用于测试的main()函数,涉及到的类请自行定义


int main( )
{
Circle c1(3,2,4),c2(4,5,5); //c2应该大于c1
Point p1(1,1),p2(3,-2),p3(7,3); //分别位于c1内、上、外


cout<<"圆c1: "<<c1;
cout<<"点p1: "<<p1;
cout<<"点p1在圆c1之"<<((locate(p1, c1)>0)?"外":((locate(p1, c1)<0)?"内":"上"))<<endl;
cout<<"点p2: "<<p2;
cout<<"点p2在圆c1之"<<((locate(p2, c1)>0)?"外":((locate(p2, c1)<0)?"内":"上"))<<endl;
cout<<"点p3: "<<p3;
cout<<"点p3在圆c1之"<<((locate(p3, c1)>0)?"外":((locate(p3, c1)<0)?"内":"上"))<<endl;
cout<<endl;


cout<<"圆c1: "<<c1;
if(c1>c2) cout<<"大于"<<endl;
if(c1<c2) cout<<"小于"<<endl;
if(c1>=c2) cout<<"大于等于"<<endl;
if(c1<=c2) cout<<"小于等于"<<endl;
if(c1==c2) cout<<"等于"<<endl;
if(c1!=c2) cout<<"不等于"<<endl;
cout<<"圆c2: "<<c1;
cout<<endl;


Point p4,p5;
crossover_point1(p1,c1, p4, p5);


cout<<"点p1: "<<p1;
cout<<"与圆c1: "<<c1;
cout<<"的圆心相连,与圆交于两点,分别是:"<<endl;
cout<<"交点: "<<p4;
cout<<"交点: "<<p5;
cout<<endl;
return 0;
}

提示:完成(6)时,借助解析几何的知识,推导出交点坐标,编程序解决即可。



第一部分 阅读程序

1、完成本章课后习题5和习题6中的任务。请自行改造程序,创建验证题目中涉及问题的情境,检验自己的答案是否正确。

习题5代码

#include <iostream>
#include<Cmath>
using namespace std;
class A //A为基类
{
public:
void f1( );
int i;
protected:
void f2();
int j;
private:
int k;
};


class B: public A //B为A的公用派生类
{
public:
void f3( );
protected:
int m;
private:
int n;
};


class C: public B //C为B的公用派生类
{
public:
void f4();
private:
int p;
};


int main()
{
A a1; //a1是基类A的对象
B b1; //b1是派生类B的对象
C c1; //c1是派生类C的对象
return 0;
}



习题6代码 


#include <iostream>
using namespace std;
class A
{
public:
void f1( );
protected:
void f2();
private:
int i;
};


class B: public A
{
public:
void f3( );
int k;
private:
int m;
};


class C: protected B
{
public:
void f4();
protected:
int n;
private:
int p;
};


class D: private C
{
public:
void f5();
protected:
int q;
private:
int r;
};


int main()
{
A a1;
B b1;
C c1;
D d1;
return 0;
}


2、完成本章课后习题7和习题8中的任务。请运行程序,并和自己的答案进行对照。


习题7代码


#include <iostream>
using namespace std;
class A
{
public:
A(){a=0;b=0;}
A(int i){a=i;b=0;}
A(int i,int j){a=i;b=j;}
void display(){cout<<"a="<<a<<" b="<<b;}
private:
int a;
int b;
};


class B : public A
{
public:
B(){c=0;}
B(int i):A(i){c=0;}
B(int i,int j):A(i,j){c=0;}
B(int i,int j,int k):A(i,j){c=k;}
void display1()
{
display();
cout<<" c="<<c<<endl;
}
private:
int c;
};


int main()
{
B b1;
B b2(1);
B b3(1,3);
B b4(1,3,5);
b1.display1();
b2.display1();
b3.display1();
b4.display1();
return 0;
}


习题8代码


#include <iostream>
using namespace std;
class A
{
public:
A(){cout<<"constructing A "<<endl;}
~A(){cout<<"destructing A "<<endl;}
};


class B : public A
{
public:
B(){cout<<"constructing B "<<endl;}
~B(){cout<<"destructing B "<<endl;}
};


class C : public B
{
public:
C(){cout<<"constructing C "<<endl;}
~C(){cout<<"destructing C "<<endl;}
};
int main()
{
C c1;
return 0;
}


第二部分 期中测验(在OJ平台上完成)