资源描述
第一阶段 C++中类的实现
第四章 继承性和派生类
【实验目标】
完成本章的内容以后,您将达到:
Ø 使用继承
Ø 使用继承中的构造函数和析构函数
Ø 使用多继承
本章实验给出了全面的操作步骤,请学生按照给出的步骤独立完成实验,以达到要求的实验目标。
第一阶段——指导学习(60分钟)
1. 继承
使用继承,我们能够在类之间重用函数。基类成员的可访问性根据它们是私有的、公有的还是保护成员而不同。派生类在成员只能访问基类的公有和保护成员。
当一个派生类生自多个基类时,就发生了多重继承。当基类有同名的成员函数时,我们需要使用作用域解析操作符来引用正确的类。
在下面所示的程序中,我们将使用两个基类,并从这两个基类公有派生一个类。该程序将从用户获得有关学生个人情况和成绩的信息并显示这些信息。
1) 声明基类
class Teacher//声明类Teacher(教师)
{
public://公有部分
Teacher(string nam , int a, string t);//构造函数
void display();//输出教师有关数据
protected://保护部分
string name;
int age;
string title;//职称
};
class Student//定义类Student(学生)
{
public:
Student(char nam[],char s,float sco);//构造函数
void display();//输出学生有关数据
protected:
char name1[20];
char sex;
float score;//成绩
};
2) 声明派生类
声明派生类需要指定每个基类的访问说明符。
class Graduate:public Teacher,public Student//声明多重继承的派生类Graduate
{
public:
Graduate(string nam, char nam1[],int a, char s, string t, float sco, float w):
Teacher(nam, a, t),Student(nam1, s, sco),wage(w) {}
void show()//输出研究生的有关数据
{
cout << "name:" << name << endl;
cout << "age:" << age << endl;
cout << "sex:" << sex << endl;
cout << "score:" << score << endl;
cout << "title:" << title << endl;
cout << "wages:" << wage << endl;
}
private:
float wage;//工资
};
3) 定义类的成员函数:
Teacher::Teacher(string nam , int a, string t)//构造函数
{
name = nam;
age = a;
title = t;
}
void Teacher::display()
{
cout << "name:" << name << endl;
cout << "age:" << age << endl;
cout << "title:" << title << endl;
}
Student::Student(char nam[],char s,float sco)//构造函数
{
strcpy(name1,nam);
sex = s;
score = sco;
}
void Student::display()
{
cout << "name:" << name1 << endl;
cout << "sex:" << sex << endl;
cout << "score:" << score << endl;
}
下面我们来看完整的程序。
#include <iostream>
#include <string>
using namespace std;
class Teacher//声明类Teacher(教师)
{
public://公有部分
Teacher(string nam , int a, string t);//构造函数
void display();//输出教师有关数据
protected://保护部分
string name;
int age;
string title;//职称
};
class Student//定义类Student(学生)
{
public:
Student(char nam[],char s,float sco);//构造函数
void display();//输出学生有关数据
protected:
char name1[20];
char sex;
float score;//成绩
};
class Graduate:public Teacher,public Student//声明多重继承的派生类Graduate
{
public:
Graduate(string nam, char nam1[],int a, char s, string t, float sco, float w):Teacher(nam, a, t),Student(nam1, s, sco),wage(w) {}
void show()//输出研究生的有关数据
{ cout << "name:" << name << endl;
cout << "age:" << age << endl;
cout << "sex:" << sex << endl;
cout << "score:" << score << endl;
cout << "title:" << title << endl;
cout << "wages:" << wage << endl;
}
private:
float wage;//工资
};
Teacher::Teacher(string nam , int a, string t)//构造函数
{
name = nam;
age = a;
title = t;
}
void Teacher::display()
{
cout << "name:" << name << endl;
cout << "age:" << age << endl;
cout << "title:" << title << endl;
}
Student::Student(char nam[],char s,float sco)//构造函数
{
strcpy(name1,nam);
sex = s;
score = sco;
}
void Student::display()
{
cout << "name:" << name1 << endl;
cout << "sex:" << sex << endl;
cout << "score:" << score << endl;
}
int main()
{
Graduate grad1("Wang-li","Wang-li",24,'f',"assistant",89.5,1234.5);
grad1.show();
return 0;
}
编译通过后,运行程序结果如图4.1:
图4.1:运行结果
2. 继承的工作方式
当在基类和派生类中都使用构造函数时,基类在派生类之前就被初始化,根据派生类的构造函数代码使用默认构造函数或带有参数的构造函数。基类构造函数的调用顺序与基类在派生类声明中声明的顺序相同,最后调用派生类的构造函数。
析构函数的调用顺序与构造函数的调用顺序相反,首先调用派生类的析构函数,然后调用基类的析构函数。
在下面的程序中,我们将看到在使用多重继承时如何调用构造函数和析构函数。这些类都有默认的构造函数和析构函数。
编译并执行下面程序:
#include <iostream.h>
class A
{
public:
A()
{
cout << "类A的构造函数" << endl;
}
~A()
{
cout << "类A的析构函数" << endl;
}
};
class B:public A
{
public:
B():A()
{
cout << "类B的构造函数,从A派生而来" << endl;
}
~B()
{
cout << "类B的析构函数" << endl;
}
};
class C:public A
{
public:
C():A()
{
cout << "类C的构造函数,从A派生而来" << endl;
}
~C()
{
cout << "类C的析构函数" << endl;
}
};
class D:public C,public B
{
B b;//基类对象
public:
D():C(),B()
{
cout << "类D的构造函数,从B和C派生而来,\n" << "内部有一个B对象" << endl;
}
~D()
{
cout << "类D的析构函数" << endl;
}
};
void main()
{
cout << "定义类C的一个对象\n";
C cc;
cout << endl;
cout << "定义类D的一个对象\n";
D dd;
cout << endl;
}
编译通过后,运行程序结果如图4.2所示:
图4.2:运行结果
上述程序中定义了四个类。一个基类A,从它直接派生了两个类B和C。对于类D,类A是一个间接基类,而类B和C是直接基类。类D还有一个数据成员,它是类B的一个对象。
仔细研究输出结果以了解调用构造函数的顺序。C类型的对象的构造函数所产生的输出结果是很简单的。
当我们考虑D类型的对象时,可以看到首先调用的是A的构造函数。可以看到基类C和B的构造函数按照在类D的声明中声明的顺序出现。
class D:public C,public B
首先调用类C的构造函数,然后调用B的构造函数。在调用完C和B的构造函数后,会看到两次调用了B的构造函数。因为在类D中有一个B类型的对象,该对象是在产生类D的构造函数之前被初始化的。
C和D类型的对象的析构函数所产生的输出结果说明析构函数的调用顺序正好和构造函数的调用顺序相反。
上述程序的输出结果如图3.2所示。
图3.2:输出结果
第二阶段——练习(60分钟)
习题一: 派生类成员的访问属性
让我们来看下列代码:
class Student//声明基类
{
public://基类公有成员
void get_value()
{
cin >> num >> name >> sex;
}
void display()
{
cout << "num: " << num << endl;
cout << "name: " << name << endl;
cout << "sex: " << sex << endl;
}
private://基类私有成员
int num;
string name;
char sex;
};
class Student1:public Student//以public方式声明派生类Student1
{
public:
void get_Value1()
{
cin >> age >> addr;
}
vid display_1()
{
cout << "num: " << num << endl;//企图引用基类的私有成员,错误
cout << "name: " << name << endl;//企图引用基类的私有成员,错误
cout << "sex: " << sex << endl;//企图引用基类的私有成员,错误
cout << "age: " << age << endl;//引用派生类的私有成员,正确
cout << "address: " << addr << endl;//引用派生类的私有成员,正确
}
private:
int age;
string addr;
};
以上代码并不完整,请补充和改写上述代码为一个完整、正确的程序,用公用继承方式。在程序中应包括输入数据的函数,在程序运行时输入num,name,sex,age,addr的值,程序应输出以上5个数据的值。
步骤如下:
a.在类Student1中,num,name和age是父类Student的私有成员,即便是公有继承也不能在派生类Student1中被直接使用,所以修改派生类Student1的定义如下:
class Student1:public Student//以public方式声明派生类Student1
{
public:
void get_Value1()
{
cin >> age >> addr;
}
void display_1()
{
cout << "age: " << age << endl;//引用派生类的私有成员,正确
cout << "address: " << addr << endl;//引用派生类的私有成员,正确
}
private:
int age;
string addr;
};
b.如果需要运行程序必须要有主函数,增加主函数,其内容为:定义派生类的对象;通过派生类的对象调用基类的方法get_value(),用来进行派生类属性num,name,sex的输入,调用派生类的对象的方法 get_value1()来实现派生类属性age,addr的输入;通过派生类调用基类的display()实现其私有成员的输出,调用派生类的display1()方法,实现派生类私有成员的输出。代码如下:
void main()
{
Student1 stud;//定义派生类Student的对象stud
stud.get_value();
stud.get_value1();
stud.display();
stud.display_1();
}
完成代码编写后,编译运行。
习题二: 派生类成员的访问属性
(1)修改补充下列代码,使代码能够实现输入数据,及显示输出数据的功能:
#include <iostream>
#include <string>
using namespace std;
class Student//声明基类
{
public://基类公有成员
void get_value()
{
cin >> num >> name >> sex;
}
void display()
{
cout << "num: " << num << endl;
cout << "name: " << name << endl;
cout << "sex: " << sex << endl;
}
protected://基类私有成员
int num;
string name;
char sex;
};
class Student1:protected Student//以public方式声明派生类Student1
{
public:
void get_value1()
{
cin >> age >> addr;
}
void display_1()
{
cout << "num: " << num << endl;
cout << "name: " << name << endl;
cout << "sex: " << sex << endl;
cout << "age: " << age << endl;//引用派生类的私有成员,正确
cout << "address: " << addr << endl;//引用派生类的私有成员,正确
}
private:
int age;
string addr;
};
void main()
{
Student1 stud;//定义派生类Student的对象stud
stud.display_1();
stud.num = 10023;
}
提示:以保护方式实现派生类
编译运行如上程序,使程序能够完成题目要求。
(2)修改上述代码,改为公用继承方式。上机调试程序,使之能正确运行并得到正确的结果。对这两种继承方式作比较分析,考虑在什么情况下二者不能互相代替。
第三阶段——作业
作业一
分别定义Teacher(教师)类和Cadre(干部)类,采用多重继承方式由这两个类派生出新类Teacher_Cadre(教师兼干部)。要求。
1. 在两个基类中都包含姓名、年龄、性别、地址、电话等数据成员。
2. 在Teacher类中还包含数据成员title(职称),在Cadre类中还包含数据成员post(职务),在Teacher_Cadre类中还包含数据成员wages(工资)。
3. 对两个基类中的姓名、年龄、性别、地址、电话等数据成员用相同的名字,在引用这些数据成员时,指定作用域。
4. 在类体中声明成员函数,在类外定义成员函数。
5. 在派生类Teacher_Cadre的成员函数show中调用Teacher类中的display函数,输出姓名、年龄、性别、职称、地址、电话,然后再用cout语句输出职务与工资。
展开阅读全文