实验四 类的继承与多态实验

本文通过实例展示了C++中继承、派生类、构造函数和析构函数的使用,探讨了虚基类解决二义性问题的作用,以及运算符重载在复数运算中的应用。同时,讨论了组合与继承的区别、公有继承等不同继承方式的适用场景,以及虚基类、静态联编和动态联编的概念。
摘要由CSDN通过智能技术生成

【实验目的】

1.理解软件重用性的一种形式——继承。

2.能够通过继承已有的类创建新类。

3.理解基类和派生类的概念。

4.能够在派生类中使用构造函数和析构函数

5.学习虚基类在解决二义性问题中的作用。

6.熟悉多态分类,理解静态联编和动态联编概念。

7.掌握运算符重载方法。

【实验内容】

1.分析程序,写出下列程序的运行结果:

(1) #include<iostream.h>

class Base

{

private:

int base_priv_dat;

protected:

int base_prot_dat;

public:

void base_show();

};

class Derived:public Base

{

private:

int derived_priv_dat;

public:

void derived_show();

};

void Base::base_show()

{

base_priv_dat=1; //基类函数可以操纵私有和保护型基类数据

base_prot_dat=2;

cout<<"base_priv_dat="<<base_priv_dat<<'\t'

<<" base_prot_dat="<<base_prot_dat<<endl;

}

void Derived::derived_show()

{

derived_priv_dat=3;

base_prot_dat=4; //派生函数可以处理保护型基类数据,但不能处理私有基类数据

cout<<"derived_priv_dat="<<derived_priv_dat<<'\t'

<<"base_prot_dat="<<base_prot_dat<<endl;

base_show(); //派生函数可以调用公有基类函数

}

int main()

{

Derivedd_obj;

d_obj.base_show(); //可用派生对象调用基类函数

d_obj.derived_show();

return(0);

}

定义派生对象,分别调用基类函数base_show()和派生类函数derived_show();基类函数base_show()把1和2分别赋值给其私有数据成员base_priv_dat和保护数据成员base_prot_dat然后将其输出;

而派生类函数derived_show()把3和4分别赋值给其私有数据成员derived_priv_dat和基类的保护数据成员base_prot_dat,然后将其输出;最后调用基类函数base_show()将其私有数据成员base_priv_dat和保护数据成员base_prot_dat输出;

(2) #include<iostream.h>

#include<string.h>

class Person

{

public:

Person(const char* s) //带参数的构造函数

{

name=newchar[strlen(s)+1];

strcpy(name,s);

}

~Person(){delete []name;} //析构函数做清理工作

char *GetName(){return name;}

protected:

char *name;

};

class Student:public Person

{

char*major;

public:

Student(constchar * s,const char *m):Person(s) //派生类构造函数

{major=newchar[strlen(m)+1];strcpy(major,m);}

~Student(){delete[]major;} //派生类析构函数

char*GetMajor(){return major;}

};

int main()

{

Studentstu("WZQ","Electric automatization");

cout<<"studentName is:"<<stu.GetName()<<" Major is:"

<<stu.GetMajor()<<endl;

return(0);

}

定义派生对象stu同时将参数”WZQ"和"Electric automatization”分别传给字符型指针s和m,再通过s将参数”WZQ"传给基类person并将其赋值给Name;而参数"Electric automatization”则通过派生类函数传给Major;然后通过派生对象stu调用基类函数GetName()和派生类函数GetMajor()将Name和Major显示出来;

2.编译运行下列程序,分析出现编译错误的原因,并给出解决办法。

#include<iostream>

#include<string>

using namespace std;

class Person

{

public:

Person(stringthe_name,string the_gender,string the_id)

{

name=the_name;

gender=the_gender;

id_number=the_id;

cout<<"Person类构造函数被调用!"<<endl;

}

voidshow()

{

cout<<"姓名:"<<name<<endl;

cout<<"性别:"<<gender<<endl;

cout<<"身份证号码:"<<id_number<<endl;

}

protected:

stringname; //姓名

stringgender; //性别

stringid_number; //身份证号码

};

class Student: public Person

{

public:

Student(stringn,string g,string i,string c):Person(n,g,i)

{

classname=c;

cout<<"Student类构造函数被调用!"<<endl;

}

protected:

stringclassname; //学生所在班级

};

class Teacher: public Person

{

public:

Teacher(stringn,string g,string i,string d):Person(n,g,i)

{

department=d;

cout<<"Teacher类构造函数被调用!"<<endl;

}

protected:

stringdepartment; //教师所在单位

};

class Assistant:public Student,public Teacher

{

public:

Assistant(stringn,string g,string i,string c,string d):Student(n,g,i,c),Teacher(n,g,i,d)

{}

voiddisp()

{

show();

cout<<"班级:"<<classname<<endl;

cout<<"系部:"<<department<<endl;

}

};

int main()

{

Assistant a("李玮","男","420300199212032323","软件141","电信系");

a.disp();

return 0;

}

解决方法一:(通过作用域符号来唯一标识)

#include<iostream>

#include<string>

using namespace std;

class Person

{

public:

Person(stringthe_name,string the_gender,string the_id)

{

name=the_name;

gender=the_gender;

id_number=the_id;

cout<<"Person类构造函数被调用!"<<endl;

}

voidshow()

{

cout<<"姓名:"<<name<<endl;

cout<<"性别:"<<gender<<endl;

cout<<"身份证号码:"<<id_number<<endl;

}

protected:

stringname; //姓名

stringgender; //性别

stringid_number; //身份证号码

};

class Student: public Person

{

public:

Student(stringn,string g,string i,string c):Person(n,g,i)

{

classname=c;

cout<<"Student类构造函数被调用!"<<endl;

}

protected:

stringclassname; //学生所在班级

};

class Teacher: public Person

{

public:

Teacher(stringn,string g,string i,string d):Person(n,g,i)

{

department=d;

cout<<"Teacher类构造函数被调用!"<<endl;

}

protected:

stringdepartment; //教师所在单位

};

class Assistant:public Student,public Teacher

{

public:

Assistant(stringn,string g,string i,string c,string d):Student(n,g,i,c),Teacher(n,g,i,d)

{}

voiddisp()

{

Teacher::show();//或者是Student::show()

cout<<"班级:"<<classname<<endl;

cout<<"系部:"<<department<<endl;

}

};

int main()

{

Assistant a("李玮","男","420300199212032323","软件141","电信系");

a.disp();

return 0;

}

解决方法二:(虚基类技术)

#include<iostream>

#include<string>

usingnamespace std;

classPerson

{

public:

Person(string the_name,stringthe_gender,string the_id)

{

name=the_name;

gender=the_gender;

id_number=the_id;

cout<<"Person类构造函数被调用!"<<endl;

}

void show()

{

cout<<"姓名:"<<name<<endl;

cout<<"性别:"<<gender<<endl;

cout<<"身份证号码:"<<id_number<<endl;

}

protected:

string name; //姓名

string gender; //性别

string id_number; //身份证号码

};

classStudent:virtual public Person

{

public:

Student(string n,string g,string i,stringc):Person(n,g,i)

{

classname=c;

cout<<"Student类构造函数被调用!"<<endl;

}

protected:

string classname; //学生所在班级

};

classTeacher:virtual public Person

{

public:

Teacher(string n,string g,string i,stringd):Person(n,g,i)

{

department=d;

cout<<"Teacher类构造函数被调用!"<<endl;

}

protected:

string department; //教师所在单位

};

classAssistant:public Student,public Teacher

{

public:

Assistant(string n,string g,string i,stringc,string d):Person(n,g,i),Student(n,g,i,c),Teacher(n,g,i,d)

{}

void disp()

{

show();

cout<<"班级:"<<classname<<endl;

cout<<"系部:"<<department<<endl;

}

};

intmain()

{

Assistant a("李玮","男","420300199212032323","软件141","电信系");

a.disp();

return 0;

}

4.开发一个简单的大学人员管理程序,该程序可以管理大学的一些基本人员:学生(student)、教师(teacher)。首先设计一个虚基类person。通过该类保存人员的最基本信息:姓名(name)、年龄(age)、性别(sex)和身份证号码。然后使用该类派生出学生类student、教师类teacher,在其中添加各自的特性,如在student类中添加如下信息:专业(speciality),在teacher类中添加院系(department)等。还有部分教师在工作的同时在职修读学位,因此同时具有教师和学生双重身份,所以由student类和teacher类再次派生出stuTeacher类。为每个类定义一个输出函数print(),输出该类相关信息。

程序代码如下:

#include "iostream"

#include "string"

using namespace std;

class Person

{

private: string m_Name;

string m_Sex;

int m_Age;

public:

Person(){}

Person(stringname, string sex, int age)

{

m_Name= name;

m_Sex= sex;

m_Age= age;

}

stringPerson_Get_Name()

{

returnm_Name;

}

stringPerson_Get_Sex()

{

returnm_Sex;

}

intPerson_Get_Age()

{

returnm_Age;

}

};

class Student :virtual public Person

{

private: string m_Speciality;

public:

Student(){}

Student(stringname, string sex, int age,string speciality):Person(name,sex,age)

{

m_Speciality= speciality;

}

~Student()

{

}

stringStudent_Get_Speciality()

{

returnm_Speciality;

}

voidStu_print()

{

cout<<"学生信息:"<< endl;

cout<<"姓名:"<< Person_Get_Name()<< endl;

cout<<"性别: " <<Person_Get_Sex()<< endl;

cout<<"年龄: " <<Person_Get_Age()<< endl;

cout<<"专业: "<<Student_Get_Speciality() << endl<< endl;

}

};

class Teacher :virtual public Person

{

private: string m_Department;

public:

Teacher(){}

Teacher(stringname, string sex, int age, string department) :Person(name, sex, age)

{

m_Department= department;

}

~Teacher()

{

}

stringTeacher_Get_Department()

{

return m_Department;

}

voidTea_print()

{

cout<<"老师信息:" << endl;

cout<<"姓名:"<< Person_Get_Name()<< endl;

cout<<"性别: " <<Person_Get_Sex()<< endl;

cout<<"年龄: " <<Person_Get_Age()<< endl;

cout<<"学院: "<<Teacher_Get_Department()<< endl<< endl;

}

};

class StuTeacher :public Student,publicTeacher

{

public:

StuTeacher(){}

StuTeacher(stringname, string sex,int age, stringspeciality,string department):Person(name,sex,age),Student(name,sex,age,speciality),Teacher(name, sex, age, department)

{

}

~StuTeacher()

{

}

voidStu_Tea_print()

{

cout<<"在读老师信息:" << endl;

cout<<"姓名:"<< Person_Get_Name()<< endl;

cout<<"性别: " <<Person_Get_Sex()<< endl;

cout<<"年龄: " <<Person_Get_Age()<< endl;

cout<<"专业: "<<Student_Get_Speciality() << endl;

cout<<"学院: "<<Teacher_Get_Department()<< endl;

}

};

int main()

{

Studentstudent(" 李玮","男", 22, "电气工程及其自动化");

student.Stu_print();

Teacherteacher("王老师","女", 33, "科技学院");

teacher.Tea_print();

StuTeacher stutracher("王伟", "男", 38," 计算机专业", "科技学院");

stutracher.Stu_Tea_print();

return0;

}

5. 用运算符重载设计复数类,实现复数的+、-、*、/运算。

#include <iostream>

#include <iomanip>

using namespace std;

class Complex

{

public:

Complex();

Complex(double r,double i);

Complex operator+(Complex &c2);

Complex operator-(Complex &c2);

Complex operator*(Complex &c2);

Complex operator/(Complex &c2);

void display();

private:

double real;

double imag;

};

//************************************************************

Complex::Complex(double r,doublei):real(r),imag(i){}//复数相加:(a+bi)+(c+di)=(a+c)+(b+d)i.

Complex Complex::operator+(Complex&c2)

{

returnComplex(real+c2.real,imag+c2.imag);

}

//复数相减:(a+bi)-(c+di)=(a-c)+(b-d)i.

Complex Complex::operator-(Complex&c2)

{

returnComplex(real-c2.real,imag-c2.imag);

}

//复数相乘:(a+bi)(c+di)=(ac-bd)+(bc+ad)i.

Complex Complex::operator*(Complex&c2)

{

returnComplex(real*c2.real-imag*c2.imag,real*c2.imag+imag*c2.real);

}

//复数相除:(a+bi)/(c+di)=(ac+bd)/(c^2+d^2)+(bc-ad)/(c^2+d^2)i

Complex Complex::operator/(Complex&c2)

{

returnComplex((real*c2.real+imag*c2.imag)/(c2.real*c2.real+c2.imag*c2.imag),(imag*c2.real-real*c2.imag)/(c2.real*c2.real+c2.imag*c2.imag));

}

void Complex::display()

{

cout<<""<<real<<"+"<<imag<<"i"<<endl;

}

int main()

{

double real,imag;

cout<<"请输入第一个复数的实部和虚部:"<<endl;

cin>>real>>imag;

Complex c1(real,imag);

cout<<"请输入第二个复数的实部和虚部:"<<endl;

cin>>real>>imag;

Complex c2(real,imag);

Complex c3=c1+c2;

cout<<"c1+c2=";

c3.display();

c3=c1-c2;

cout<<"c1-c2=";

c3.display();

c3=c1*c2;

cout<<"c1*c2=";

c3.display();

c3=c1/c2;

cout<<"c1/c2=";

c3.display();

return 0;

}

【思考题】

1.组合与继承的区别是什么?

2.公有继承、保护继承和私有继承分别在什么情况下使用?

3.什么是虚基类?有何作用?

4.静态联编和动态联编有什么区别?

5.简述空的虚函数与纯虚函数的区别?

6.简述抽象类和具体类的区别?

1.

答:1)组合关系可以显式地获得被包含类的对象,而继承则是隐式地获得父类的对象,被包含类和父类对应,而组合外部类和子类对应

2)组合关系在运行期决定,而继承关系在编译期就已经决定了。

3)组合是在组合类和被包含类之间的一种松耦合关系,而继承则是父类和子类之间的一种紧耦合关系。

4)当选择使用组合关系时,在组合类中包含了外部类的对象,组合类可以调用外部类必须的方法,而使用继承关系时,父类的所有方法和变量都被子类无条件继承,子类不能选择。

5)最重要的一点,使用继承关系时,可以实现类型的回溯,即用父类变量引用子类对象,这样便可以实现多态,而组合没有这个特性

2.

答:1)公有继承时基类中各成员属性保持不变,基类中private成员被隐藏。派生类的成员只能访问基类中的public/protected成员,而不能访问private成员;派生类的对象只能访问基类中的public成员。

2)私有继承时基类中各成员属性均变为private,并且基类中private成员被隐藏。派生类的成员也只能访问基类中的public/protected成员,而不能访问private成员;派生类的对象不能访问基类中的任何的成员。

3)保护继承时基类中各成员属性均变为protected,并且基类中private成员被隐藏。派生类的成员只能访问基类中的public/protected成员,而不能访问private成员;派生类的对象不能访问基类中的任何的成员。

3.

答:为了类的继承在派生类继承基类时,加上一个virtual关键词则为虚拟基类继承。

作用:虚基类主要解决在多重继承时,基类可能被多次继承,虚基类主要提供一个基类给派生类。

4.

答:静态联编说的是在编译时就已经确定好了调用和被调用两者的关系。

动态联编说的是程序运行时才确定调用和被调用者的关系。

5.

答:1)纯虚函数只有定义,没有实现;而虚函数既有定义,也有实现的代码

纯虚函数一般没有代码实现部分。

  1. 2)包含纯虚函数的类不能定义其对象,而包含虚函数的则可以。

6.

答:

抽象类是不可被实例化的类,即它可以没有直接实例,这既可能是因为它的描述是不完整的(如缺少一个或多个操作的方法),也可能是因为即使它的描述是完整的它也不想被实例化。抽象类是为了以后说明。抽象类必须有可能含有实例的后代才能使用,一个抽象的叶类是没用的(它可以作为叶在框架中出现,但是最终它必须被说明)。

具体类可以没有任何抽象操作(否则,它必为抽象的),但是抽象类可以有具体操作。具体操作是可以被实现一次并在所有子类中不变地使用的操作。在它们的实现中,具体操作可以只使用声明它们的类所知道的特征(属性和操作)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

挚爱宁静

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

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

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

打赏作者

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

抵扣说明:

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

余额充值