天津理工大学C++期末考试

更新时间:2024-04-10 03:31:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

实验一

一、 明确的概念:

(1)理解类和对象的概念;(具体见附一)

类是抽象的 对象是具体的 例如:你、我、他 都是人 那么 你、我、他就是对象 人就是类

(2)掌握类与对象的定义方法;

类的定义:

class 类名{ … /*定义这个类*/}; //(别忘了最后的分号) 对象的定义: 类名 对象名(参数);

(3)理解类的成员的访问控制的含义,公有和私有成员的区别;

public://访问属性为公有 通过外部直接访问 即:对象名.成员名或成员函数 private://访问属性为私有 不能通过外部直接访问(不声明访问属性时 系统默认为私有) 当出现对象名.成员(私有)时 编译器报错

protected://访问属性为保护 与private类似 但protected属性的成员可以继承 private不能继承

(4)掌握构造函数和析构函数的含义与作用、定义方式和实现;

构造函数:为数据成员开辟存储空间 函数名必须与类名相同 之前绝对不许说明返回值类型 void也不行 构造函数不能由用户调用 即:对象名.构造函数名(参数)是错误的 构造函数是随着对象的声明而调用的 例如: class Student{Student(){cout<<”Hello.”<

{cout<<”Hello.”<

运行结果: Hello. //<-这个Hello是主函数中的 Hello. //<-是声明A对象时调用的构造函数 构造函数中的Hello

析构函数功能与构造函数相反 注意调用时间和顺序(看书)

1

二、 练习项目 1.

输入下列程序,按要求进行实验,并记录实验的结果。 #include using namespace std;

class Coordinate {

public:

Coordinate(int x1, int y1){x=x1; y=y1;} Coordinate(Coordinate &p); ~Coordinate(){cout<<\ int getx(){return x;} int gety(){return y;} private: int x, y; };

Coordinate::Coordinate(Coordinate &p){//拷贝构造函数 x=p.x; y=p.y; cout<<\}

int main(){ Coordinate p1(3,4); 调用构造函数 调用拷贝构造函数(见书P89) Coordinate p2(p1); Coordinate p3=p2; cout<<\

程序结束时 调用析构函数 注意析构函数 return 0; 的调用顺序 从上至下 依此为 p3 p2 p1的}

析构函数 附:如何知道 该程序析构函数的调用顺序是p3 p2 p1 ? 答:将拷贝构造函数中 改为x=2*p.x; y=2*p.y 析构函数中 在cout<<”Destructor is called.”之后添加<<”x=”<

(1) 记录程序的运行结果 (2) 将Coordinate类中带有两个参数的构造函数进行修改,在函数体内增加如下语句:

cout<<”Constructor is called.”<

在主函数体内,添加如下语句:

Coordinate p4; ?错误原因:构造函数没有参数 构造函数为Coordinate::Coordinate(int ,int) Coordinate p5(2); ? 错误原因:参数数量不对

根据注释语句的提示实现类Date的成员函数,并将完整的程序编译、连接成功以保证程序能够正确运行。 #include class Date{

2.

2

public:

void printDate(); //显示日期 void setDay(int); //设置日的值

分析: void setMonth(int); //设置月的值

1.题目中 Date类的数据成员为day, month, year 且均为 void setYear(int); //设置年的值

整型访问属性为私有 主函数中声明了testDay对象 private:

int day, month, year; 2.数据成员均为私有 则不能通过tesDay.day=<数值>的方}; 法来设置 题目中给出了 void setDay(int) void int main(){ setMonth(int) 和void setYear(int)三个成员函数去是指day Date testDay; month 和 year 的值 还有一个void printDate()来输出 testDay.setDay(5); 3.准备工作结束 开始编程 看程序 仅差4个成员函数未 testDay.setMonth(10); 定义 类外定义 要写出作用域 即该函数属于哪个类: testDay.setYear(2010); 格式: 返回值类型 作用域::函数名 参数表 testDay.printDate(); void Date::setDay (int d)/*定义时必须}; 要给形参一个名字 这里给的是*/d {day=d}//设置了day 的值 其他函数依此类推 输出函数就不用再唠叨了 void Date::setDay(int d){day=d;} 4.验证结果 出现溢出数据时查看是否写反了 例如写成void Date::setMonth(int m){month=m;} d=day 了解设置函数的作用机制 见附二 void Date::setYear(int y){year=y;}

void Date::printDate(){cout<

3. 下面是一个计算器类的定义,请完成该类的成员函数的实现,并设计一个主函数使用该类和相关成员函数以测试

该类设计的正确性。

#include using namespace std;

class counter {

public: counter(int number=0) //构造函数 { value=number; }

void increment(); //给value原值加1 void decrement(); //给value原值减1 int getvalue(); //取得计数器值 int print(); //显示计数 private: int value; //数据成员 };

void counter::increment(){value++;cout<<\(其中的cout语句可以不写) void counter::decrement(){value--;cout<<\

3

int counter::getvalue(){return value;}

int counter::print(){cout<<\

int main(){ cout<<\//定义counter类的几个对象并调用有关成员函数 int a; cin>>a; counter c(a); //输入a 并将a作为参数 通过构造函数为对象中的value赋值 c.increment(); c.print(); //题目要求验证 所以使用输出函数一次验证value的值 c.decrement(); c.print(); return 0; } 4.

定义一个类ClsName,要求该类设计如下: (1)该类有两个整型数据成员x和y;

(2)为该类重载三个不同的构造函数:分别为无参数、带一个参数和带两个参数的构造函数,要求在构造函数中输出必要的信息以示区别;

(3)设计2个成员函数用来读取数据成员x和y; (4)设计2个成员函数用来设置数据成员x和y;

(5)设计1个成员函数用来在屏幕上打印输出数据成员x和y;

(6)在main()函数中用三个不同的构造函数创建3个对象,并使用所有的成员函数对这些对象进行必要的操作。

class ClsName {

public: int a,b; ClsName(int a,int b){cout<<\//以下三个(2)中要求的重载构造函数 ClsName(int a){cout<<\题目要求加以区别,所以cout输出不同内容加以区分 ClsName(void){cout<<\ int getx(){return x;} ?因为x,y的访问属性为私有,不能由主函数直接访问 所以会设置读取函数专门负责返回相应的值 int gety(){return y;}

重载:函数名相同,参数的类型不同或者 void setx(){cout<<\

个数不同、或者都不同。 即根据带入参数 void sety(){cout<<\

的类型、数量的不同,来实现不同的功能 void print(){cout<<\private:

int x,y; ?(1)中要求的两个整型数据成员 };

int main() { int a,b; cout<<\ cin>>a;cin>>b; ClsName t1(a,b);

4

t1.print(); t1.setx();t1.sety(); t1.print(); cout<<\number:\ cin>>a; ClsName t2(a); t2.print(); t2.setx();t2.sety(); t2.print(); cout<<\ ClsName t3; t3.print(); t3.setx();t3.sety(); t3.print(); return 0; 5. 建立类cylinder,包括两个数据成员radius和height,分别表示圆柱体的半径和高度, cylinder类的构造函数被传递了两个double值来初始化这两个成员;定义成员函数area()和volume用来求圆柱体的表面积和体积,定义成员函数print()打印cylinder类的相关信息。最后,在主函数中对cylinder类的设计进行测试。 这题很简单 没啥说的

#include class cylinder { public: }; int main() { }

int a,b; cylinder v; cout<<\cin>>a;

cout<<\cin>>b; v.set(a,b); v.print(); return 0;

void set(double r,double h){radius=r,height=h;} double area(){return (radius*3.14);} double volume(){return (height*area());}

void print(){cout<<\olume=\double radius,height;

private:

5

6.

定义一个学生类CStudent实现简单的学籍管理功能,要求该类至少实现以下功能:

(1) 录入学生的基本信息(包括姓名,学号,性别,年龄,专业,入学时间,各门功课成绩) (2) 输出学生的基本信息

(3) 选课(输入时间和所选的课程) (4) 统计每门课的学分绩点 (5) 统计每学期的平均学分绩点 (6) 统计重考科目 (7) 统计重修科目 #include #include using namespace std; const MAX=4; class CStudent{ string name,sex,ID,object,jtime;//分别存储姓名 性别 学号 专业 入学时间 int age; //存储年龄 int mark[MAX]; //设立一个数组存放成绩 string sbj[MAX]; //设立string数组来存放科目名称 int retry,redo; //统计重考重修数量 string t_chose,s_chose; //存放选课时间和选课名称 int m_point[MAX],m_mark[MAX]; //存放每门功课的学分和绩点 int marker[MAX]; //存放重修科目的角标(有时不止挂掉一科 可能会很多 所以声明称数组) int marker2[MAX]; //存放重修科目角标 public: CStudent()

为什么建立数据时使用的数组? {

通过对角标的控制 便可以把一行数据全部对 cout<<\构造CStudent 开始录入基本信息\应起来 cout<<\

cout<<\

请看下面数据对应关系: cout<<\

角标 科目名称成绩学分 cout<<\

(sbj[i]) (mark[i]) (m_mark[i]) cout<<\

0 44 6 数学 cout<<\

1 92 6 C语言 cout<<\

2 72 4 英语 for(int i=0;i

便于统计也可以方便地调用出一门科目的 {

全部内容 cout<<\

cout<<\ } } void baseprint() //按(2)要求 输出基本信息 { cout<<\基本信息:\ cout<<\学生姓名:\学号:\年龄:\性别\ cout<<\入学时间:\专业:\ cout<<\成绩:\

6

for(int i=0;i

retry=0; for(i=0;i=60)score+=m_mark[i]; //成绩及格垒加学分 else {retry++;marker[j++]=i;} //否则不及格 便要重考 将重考数量自增 } //其中marker[j++]=i是将当时重修科目的角标记录下来 float s=0; for(i=0;i

7

for(int i=0;i

int main(void) { CStudent a; a.baseprint(); a.chose(); a.Point(); a.check(); return 0; }

注意:

(1)新设计的类中所需要的数据成员需要根据所要实现的功能自行设计;

(2)用一个演示程序完成对所设计的新类的功能测试,并给出测试数据和实验结果; (3)为增加程序可读性,请在程序中对类成员进行适当注释说明;

补充实验题:

(1)教材134页【3.33】-【3.36】

8

实验二

(2010-3-23)

实验名称:

复杂形式的对象。

实验目的:

(1)掌握对象数组、对象指针和string类的使用方法;

把对象想象成一种数据类型 比如整型 有整型数组吧(int a[10])自然也有对象数组 对象指针以以上类似 有时涉及到动态联编()

String类 不如说是string类型 类似于智能化的字符串数组

(2)掌握对象数组、对象指针和对象引用作为函数参数的使用方法;

主要看书 实际用的不多 注意对象数组初始化方法(书P77中上的说明)

(3)掌握类对象作为成员的使用方法;

了解就行

(4)掌握友元的概念和使用方法;

通常的,通过A对象想要访问B对象的私有成员是不可能的 而通过友元就可以做到 需要注意的是 友元函数虽然在类内声明 但是友元函数不是成员函数 独立于类外 所以类外定义是不能加作用域“::”

另外,由于使用的Visual C++6.0不是完全使用C++标准 编程时如果遇到 报错内容为一堆大写字母 且错误位置指向友元函数的话 把#include using namespace std;改为#include 还有!只有上述情况才可以把头文件加上“.h”,否则会导致部分功能不正常

(5)掌握静态数据成员和静态成员函数的使用方法;

例如:有Object类,拥有数据成员a,由Object类声明出的对象A、B、C,那么A、B、C都拥有各自的a,内存中也会分配出各自的内存空间A::a,B::a,C::a(共3个)。而如果将数据成员a声明为静态成员(static),那么A、B、C则共用一个内存空间a(只有1个)

最典型的例子是统计声明对象的数量 使用方法:

static 数据类型 数据成员名

由于不能直接对数据成员赋初值 所以静态数据成员初始化方法为: 数据类型 类名::静态数据成员名=

9

初值(注意:1.是类名,不是对象名;2.之前不要加static)

静态成员函数

静态成员函数属于整个类 而不是某个对象 所以调用方法为 类名::静态成员函数名(参数表) 其他参看书P103几点说明

练习项目

Time类的框架定义如下:

#include //Powered by Zuki & X.Duke class Time { public:

Time(int A=0,int B=0,int C=0) // 带默认参数的构造函数 { }

// set functions

void setTime(int a,int b,int c) { } { } {

for(;;) {

if(a>=60||a<0)

10

for(;;) { } hour=a;

if(a>=24||a<0) {

cout<<\小时输入错误 再来一次\cin>>a; }

else {break;}

cout<<\setHour(a); setMinute(b); setSecond(c);

// 设置hour, minute, second

hour=A; minute=B; second=C;

//声明Time类

}

// 设置second (确保数据在合理

{

cout<<\分钟输入错误 再来一次\cin>>a; }

else {break;} } minute=a;

void setSecond( int a) 范围)

{ }

for(;;) {

if(a>=60||a<0) {

cout<<\秒输入错误 再来一次\cin>>a; } else {break;} } second=a;

void setHour(int a)// 设置hour (确保数据在合理范围)

// get functions

int getHour()// 返回 hour

{ } { } { }

return second; return minute; return hour;

int getMinute()// 返回 minute

int getSecond()// 返回 second

void setMinute(int a) // 设置minute (确保数据在合理范围)

void printUniversal()// 按24小时格式输出时间:23:56:12

dl; l; private:

int hour;

// 0 - 23 (24小时格式)

cout<

void printStandard()// 按12小时格式输出时间:11:56:12 (PM) { if (hour>12)

cout<<(hour-12)<<\cout<

int minute; // 0 - 59 int second; // 0 - 59

}; // Timel类定义结束 int main() {

Time t; int a,b,c;

cout<<\设置小时:\cin>>a;

cout<<\设置分钟:\cin>>b;

cout<<\设置秒:\cin>>c; t.setTime(a,b,c); t.printStandard(); t.printUniversal(); return 0;

或 9:23:55(AM)

2.设计一个用来表示直角坐标系的Location类,在主程序中创建类Location的两个对象A和B,要求A的坐标在第3象限,B的坐标点在第2象限,分别采用成员函数和友元函数计算给定两个坐标点之间的距离,要求按如下格式输出结果:

A(x1, y1), B(x2, y2) Distance1=d1 Distance2=d2

其中:x1, x2, y1, y2为指定的坐标值,d1和d2为两个坐标点之间的距离。Location类框架可参考如下:

#include #include class Location { public: 离

11

Location(double,double); double Getx(); double Gety();

//构造函数

//成员函数,取x坐标的值 //成员函数,取y坐标的值

//声明类Location

friend double distance2(Location &A, Location &B)//友元函数,求两坐标点之间的距离

{ }

return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));

~Location(void){cout<<\private: };

double x,y;

double distance1(Location&);//成员函数,求两坐标点之间的距

Location::Location(double a,double b) { }

double Location::Getx() { }

double Location::Gety() { }

double Location::distance1(Location &L) { } int main() {

double a,b;

cout<<\输入A点坐标(在第二象限):\cout<<\for(;;) { }

cin>>a; if(a<0)break;

cout<<\不对,再来一次:\return sqrt((L.x-x)*(L.x-x)+(L.y-y)*(L.y-y)); return y; return x; x=a; y=b;

}

cout<<\for(;;) { }

Location A(a,b);

cout<<\输入B点坐标(在第四象限):\cout<<\for(;;) { }

cout<<\for(;;) { }

Location B(a,b);

cout<<\cout<<\cout<<\cout<<\return 0;

cin>>b; if(b<0)break;

cout<<\不对,再来一次:\cin>>a; if(a>0)break;

cout<<\不对,再来一次:\cin>>b; if(b>0)break;

cout<<\不对,再来一次:\

3.

使用C++的string类,将5个字符串按逆转后的顺序显示出来。例如,逆转前的5个字符串是: Germany Japan America Britain France 逆转后的顺序输出字符串是:

12

France Britain America Japan Germany

#include #include using namespace std; int main(void) { }

string str1,str2,str3,str4,str5; cin>>str1>>str2>>str3>>str4>>str5;

cout<

4.

设计一个模仿类magic来实现4*4的魔方阵。类的框架如下:

#include using namespace std; class magic { public: };

void magic::getdata() { }

void magic::setfirstmagic() {

int temp;

temp=m[0][0]=first; for(int i=0,j=0;i<4;i++)

for(j=0;j<4;j++) { }

if(i==0&&j==0)continue; temp+=step; m[i][j]=temp;

cout<<\cout<<\void getdata(); int generate();

//输入初值成员函数 //生成最终魔方成员函数

void setfirstmagic(); //设置初始魔方成员函数 int printmagic(); int m[4][4]; int step; int first; int sumj;

//显示魔方成员函数

//声明魔方阵类magic

}

int magic::generate() { }

int magic::printmagic() { } { }

magic m; m.getdata(); m.setfirstmagic(); m.generate(); m.printmagic(); return 0; cout<

for(j=0;j<4;j++)

cout<

for(i=0,j=3;i<4;i++,j--) { } return 0;

m[i][j]=sumj-m[i][j]; m[i][i]=sumj-m[i][i];

private:

int main(void)

sumj=m[0][0]+m[3][3];

13

所谓4*4的魔方阵,是指该矩阵的各行值的和等于各列值的和,并等于两对角线值的和,如: ?31??9?17??725??211915?,其各行、各列以及对角线值的和都是64。 131123??27291?35求4*4的魔方阵的一般步骤提示如下:

设置初始魔方的起始值和相邻元素之间的差值。例如上述魔方阵的初始魔方的起始值和相邻元素之间的差值分别为:first=1, step=2

设置初始魔方元素的值。例如上述魔方的初始魔方阵为: ?1??9?17??257??111315? 192123??272931?35生成最终魔方阵。方法如下:

1求最大元素和最小元素的和sum,本例为1+31=32。 ○

2用32减去初始魔方阵所有对角线上元素的值,然后将结果放在原来的位置,即可求得最终的魔方阵。本例最终○

魔方阵为: ?31??9?17??725??211915? 131123??27291?35编写主程序,测试所设计的魔方类的正确性. 5.

声明一个Employee类,数据成员包括:一个long型的id,两个字符指针成员,代表职员的姓名和家庭住址,一个double数据,代表月薪。成员函数有:构造函数、析构函数、set_salary()和get_salary()代表修改和获取薪资、set_name()和get_name()代表修改和获取姓名、set_address()和get_address()代表修改和获取家庭住址,set_id()和get_id()用来修改获取当前职员的id号。在主程序中,创建对象数组调用上述函数以测试Employee类设计的正确性。Employee类的框架可参考:

#include #include using namespace std; class Employee { public:

Employee(long = 0,char* = \~Employee();

// set functions void set_id(long);

// 设置id // 设置salary

void set_salary(double);

// 析构函数

构造函数

//声明Employee类

// get functions

long get_id();

// 返回id

double get_salary(); char* get_name(); private: long id;

// 工号 // 姓名 // 家庭住址 // 月薪

char *name; char *address; double salary;

Employee::Employee(long , char *, char *, double ) 14

// 返回 salary // 返回 name

char* get_addressSecond(); // 返回 address void print(); // 打印输出Employee的相关信息

void set_name(char* ); void set_address(char* );

// 设置name // 设置adress

}; // Employee类声明结束

{ }

void Employee::set_address(char *q) { }

void Employee::set_id(long a) { }

void Employee::set_name(char *z) { }

void Employee::set_salary(double a) { }

long Employee::get_id() { }

double Employee::get_salary() { }

char* Employee::get_name() { }

char* Employee::get_addressSecond() // 返回 address { }

Employee::~Employee() {}

void Employee::print() {

cout<<\cout<<\姓名::\cout<<\住址:\

}

return 0;

==============\月薪:\

return address; return name; return salary; return id; salary=a; name=z; id=a; address=q; name=new char; address=new char;

}

int main(void) {

cout<<\输入要统计的员工数量:\int i;cin>>i; int j=0,a; double b;

cout<<\录入信息===\Employee s[1000]; char *p; for(;j

for(j=0;j

s[j].print();

cout<<\输入员工ID:\cin>>a; s[j].set_id(a); p=new char[1000];

cout<<\员工姓名:\s[j].set_name(p); p=new char[1000];

cout<<\员工住址:\s[j].set_address(p); cout<<\输入员工工资:\cin>>b; s[j].set_salary(b);

15

6.

声明一个Student类,在该类中包括一个数据成员:score(代表课程成绩)、两个静态数据成员:total_score(代表总分),count(代表学生总人数)。成员函数有:构造函数、析构函数、account(int)用于设置分数、静态成员函数sum()返回所有学生的总成绩、静态成员函数average()返回所有学生的平均成绩、print()用于打印当前学生对象的成绩等。在主程序中,输入某班同学的成绩,并调用上述函数打印全班同学的成绩、求出全班学生的成绩之和与平均分等。Student类的框架可参考:

#include #include using namespace std; class Student { public: private: int score; 人数

}; // Student类声

Student::Student(int) { }

Student::~Student() {}

void Student::account(int a) { }

int Student::sum() { }

return Student::total_score; score=a;

total_score+=score; count++;

}

cout<<\输出全班成绩:\int j=1; while(i>0) { }

s[0].print2(); return 0;}

s[--i].print();

if(j++%6==0)cout<

score=0;

// 分

static int total_score;

// 总分

//

static int count;

Student(int =0); // 构造函数 ~Student();

void account(int); static int sum(); void print2();

//

// 设置分数 // 返回总成绩

打印输出Student的平均成绩和总成绩 // 析构函数

//声明Student类

double Student::average() { }

void Student::print() { }

void Student::print2() { }

int Student::count=0; int Student::total_score=0; int main(void)

{

int i=0,a; Student s[100];

cout<<\开始录入成绩,输入-1结束\while(i>=0) {

cin>>a; if(a<0) { }

cout<<\成绩录入结束\

cout<<\全班统计:\\n总成绩:\平均成

绩:\

cout<

return Student::total_score/double(Student::count);

static double average();// 返回平均成绩

打印输出Student的相关信息

void print(); //

s[i++].account(a);

注意:静态成员和非静态成员的初始化方式的区别。

16

实验三 派生与继承

(2010-3-23)

三、 实验名称:

派生与继承。

四、 实验目的:

(1) 理解继承的含义,掌握派生类的定义方法和实现;

继承就是子承父类 看书注意格式 私有成员不能继承 父类的保护成员继承成变为子类的私有成员

(2) 理解公有继承下基类成员对派生类成员和派生类对象的可见性,能正确地访问继承层次中的各种类成

员;

(3) 理解保护成员在继承中的作用,能够在适当的时候选择使用保护成员以便派生类成员可以访问基类的

部分非公开的成员;

(4) 理解虚函数在类的继承层次中的作用,虚函数的引入对程序运行时的影响,能够对使用虚函数的简单

程序写出程序结果。

五、 练习项目

1.先定义“点”类Point,再由“点”类派生出“圆”类Circle。

#include #define PI 3.14159

class Point // 定义“点”类 {

int x, y;

17

void ShowPoint( ) {

cout<<\

}

int Getx( ) {

return x; }

public:

Point(int a=0, int b=0) {

x=a; y=b; }

int Gety( )

};

{ return y; }

}

void ShowCircle( ) { }

ShowPoint( ); // F cout<<\

cout<<\ //G

void Setxy(int a, int b) {

x=a; y=b; }

};

class Circle: public Point // 定义“圆”类,公有继承 {

int r; // “圆”的半径

void main( ) { }

Circle c(1, 1, 1); c.ShowCircle( ); c.Move(1, 2); c.ShowCircle( );

c.Setxy(4, 5); //重新置圆心坐标 c.Setr(2); //重新置半径值 c.ShowCircle( );

public: 移

{

int x1=Getx( ); //存取基类的私有成员 int y1=Gety( ); // D x1 += x_offset; y1 += y_offset;

Setxy(x1, y1); // E 运行结果略

Circle(int x, int y, int ra) : Point(x, y) // B {

r = ra;

}

void Setr(int ra) {

r = ra; }

double Area( ) //求圆的面积 {

return PI*r*r; }

void Move(int x_offset, int y_offset) //将圆心坐标平

(1) 记录程序的运行结果

(2) 测试能否将move函数体改写为

x=x+x_offset; y=y+y_offset;

1(2)不能改写 派生类不能直接访问基类的私有成员

2: 先定义“点”类Point和“半径”类Radius,再由Point类和Radius类多重派生出“圆”类Circle。

#include #define PI 3.14159 class Point {

protected: //A

int x, y;

};

class Radius {

protected: //B

18

{ cout<<\ int Getx( ) { return x; } int Gety( ) { return y; }

void Setxy(int a, int b){ x=a; y=b; }

public:

Point(int a=0, int b=0){ x=a; y=b; } void ShowPoint( )

int r;

void ShowCircle( ) { ShowPoint( );

cout<<\cout<<\

public: Radius(int ra=0){ r = ra; } void Setr(int ra){ r = ra; } int Getr( ){ return r; }

};

}

class Circle : public Point, public Radius }; {

public: void main( ) Circle(int x, int y, int ra) : Point(x, y), Radius(ra) //D { { } Circle c(1, 1, 1);

c.ShowCircle( ); double Area( ) c.Move(1, 2); { return PI*r*r; } //直接访问基类的保护成员 c.ShowCircle( );

c.Setxy(4, 5); void Move(int x_offset, int y_offset) c.Setr(2); { x += x_offset; y += y_offset; } c.ShowCircle( );

}

(1) 记录程序的运行结果 运行结果略 (2) 为什么可以直接使用x,y, 基类的数据成员x,y为保护数据成员

相当于派生类的私有数据成员 可以被派生类的成员函数访问

(3) 如果x,y在基类中是私有的行吗?

私有则不能被访问

3. 多重继承中基类构造函数和析构函数的调用顺序 #include ~Base1( ) class Base1 {

cout<<\{

}; protected: class Base2

int data1;

{

public: protected: Base1(int a=0)

int data2; { data1 = a;

public: cout<<\

Base2(int a=0)

}

{

data2 = a;

19

}

cout<<\ }

~Base2( ) {

cout<<\ }

};

class Derived: public Base1, public Base2 {

int d;

public: Derived(int x, int y, int z):Base1(x), Base2(y)

{ d=z; cout<<\}

运行结果:

Base Constructor1 Base Constructor2 Derived Constructor 1,2,3

Derived Destructor Base Destructor2 Base Destructor1

Press any key to continue

要求记住调用顺序

4.对象成员构造函数和析构函数的调用顺序 #include class Base1 {

protected:

int data1;

public: Base1(int a=8) { data1 = a;

cout<

} ~Base1( ) {

cout<

~Derived( )

{ cout<<\ } void Show( )

{ cout<

};

void main( )

{ Derived c(1, 2, 3); c.Show( );

}

(1) 记录程序的运行结果 protected:

int data2;

public: Base2(int a=9) { data2 = a;

cout<

} ~Base2( ) {

cout<

class Derived:public Base1, public Base2 { int d;

Base1 b1, b2;

public:

Derived(int x, int y, int z) : Base1(x), Base2(y), 20

b1(x+y), b2(x+z)

{ d=z; cout<<\} ~Derived( )

{ cout<<\void Show( ) {

cout<

}

}

};

void main( ) { }

Derived c(1, 2, 3); c.Show( );

(1) 记录程序的运行结果 1, Base Constructor1 2, Base Constructor2 3, Base Constructor1 4, Base Constructor1 Derived Constructor 1,2,3

Derived Destructor 4, Base Destructor1 3, Base Destructor1 2, Base Destructor2 1, Base Destructor1

Press any key to continue

5. 编程题

假设某商店有如下几种货品:衬衣、帽子、立柜。每一种货物都有与其关联的说明信息。 衬衣:单价、产地、库存量、布料;

帽子:单价、产地、库存量、布料、样式(平顶或尖顶); 立柜:单价、产地、库存量、木料、颜色。

对这些商品的操作有:商品的进库(增加库存量),商品的出库(减少库存量),该类货 品总价格的计算。

要求自行设计数据结构,用类的继承与派生关系将上述的各种货品表示出来,并使用类 的构造函数来初始化每一类对象的初始数据。而后将上述的商品管理计算机化,完成操作要 求的功能。 【实现方法提示】

1.设立3 个不同的类来描述与处理3 种不同的货品。首先注意到上述3 种货品数据之 间的相互关联关系,可使用C++基类及其派生类的定义方法,先抽象出(“提取”出)如下每 一货品都具有的 “公有”数据构成一个所谓的基类base,而后再派生出所需的那3 个类。 (1)base(基)类:单价、产地、库存量;

(2)由base 作为基类,派生出shirt(衬衣)类:增加“布料”数据;

(3)由base 出发,派生出wardrobe(立柜)类:增加“木料”与“颜色”数据; (4)而后又由shirt 类出发(作为基类),派生出cap(帽子)类:增加“样式”数据。

21

2.对应于要对各类数据所进行的操作,而设立出类的如下几个成员函数。 (1)构造函数

通过传递来的实参数据,来构造出每一对象所具有的各数据成员。如基类base 需要传 递place、count 与price 三项数据,而派生类shirt 则需在base 数据的基础上增加第四项 即布料数据material 等。 (2)商品的进库(增加库存量) void in_something(int add_cnt);

将对象的库存量count 增加一个数量add_cnt。 (3)商品的出库(减少库存量) void out_something(int del_cnt);

将对象的库存量count 减少一个数量del_cnt。 (4)该类货品总价格的计算 double total_price();

通过使用“price*count”计算并返回对象所代表货品的总价格。 (5)对象数据的输出。

在屏幕上显示出对象所拥有的当前数据。

代码:

#include #include using namespace std; class base{ protected: string place; int count; double price; public: base(string pl,double pr,int c); void in_something(int add_cnt); void out_something(int del_cnt); };

class wardrobe:public base{ string color; string wood; public: wardrobe(string pl,double pr,int c,string co,string wo):base(pl,pr,c) { color=co; wood=wo; } void print(); };

class shirt:public base{ protected: string material;

22

public: shirt(string pl,double pr,int c,string ma):base(pl,pr,c) { material=ma; } void print(); };

class cap:public shirt{ string style; public: cap(string pl,double pr,int c,string ma,string st):shirt(pl,pr,c,ma) { style=st; } void print(); };

base::base(string pl,double pr,int c) { place=pl; price=pr; count=c;} void base::in_something(int add_cnt) { count+=add_cnt; }

void base::out_something(int del_cnt) { count-=del_cnt; if(count<0)count=0; }

void shirt::print()

{ cout<<\衬衣\\t产地:\布料:\单价:\数量:\总价:\void cap::print() { cout<<\帽子\\t产地:\布料:\样式:\单价:\数量:\总价:\void wardrobe::print() { cout<<\立柜\\t产地:\颜色:\木料:\单价:\数量:\总价:\

int main(void) { shirt s(\广州\棉\ cap c(\苏州\帆布\ wardrobe w(\福建\红色\樟木\ string a; cout<<\有如下商品:\ s.print(); c.print(); w.print(); int temp; while(a!=\ {

23

}

cout<<\输入相应物品进行相应操作(衬衣:s 帽子:c 立柜:w 结束:0)\ cin>>a; if(a==\ cout<<\为入库 -为出库 ?为查询\ if(a==\入库数量:\ if(a==\出库数量:\ if(a==\ } else if(a==\ cout<<\为入库 -为出库 ?为查询\ if(a==\入库数量:\ if(a==\出库数量:\ if(a==\ } else if(a==\ cout<<\为入库 -为出库 ?为查询\ if(a==\入库数量:\ if(a==\出库数量:\ if(a==\ } else if(a==\ else cout<<\有误 重新\}

return 0;

运行结果:

有如下商品:

衬衣 产地:广州 布料:棉 单价:55.8 数量:20 总价:1116

帽子 产地:苏州 布料:帆布 样式:A 单价:23.5 数量:30 总价:705

立柜 产地:福建 颜色:红色 木料:樟木 单价:1200 数量:10 总价:12000

输入相应物品进行相应操作(衬衣:s 帽子:c 立柜:w 结束:0) s

+为入库 -为出库 ?为查询+ 入库数量:20

输入相应物品进行相应操作(衬衣:s 帽子:c 立柜:w 结束:0) c

+为入库 -为出库 ?为查询- 出库数量:100

输入相应物品进行相应操作(衬衣:s 帽子:c 立柜:w 结束:0) w

+为入库 -为出库 ?为查询?

立柜 产地:福建 颜色:红色 木料:樟木 单价:1200 数量:10 总价:12000

24

输入相应物品进行相应操作(衬衣:s 帽子:c 立柜:w 结束:0) 0

衬衣 产地:广州 布料:棉 单价:55.8 数量:40 总价:2232

帽子 产地:苏州 布料:帆布 样式:A 单价:23.5 数量:0 总价:0

立柜 产地:福建 颜色:红色 木料:樟木 单价:1200 数量:10 总价:12000 Press any key to continue

25

实验四

(2010-4-23)

多态程序设计

实验目的:

(1)掌握运算符重载的方法; 运算符其实相当于一个函数 只不过我们平时使用的是它的隐式形式

重载是函数名不变,带入函数的参数个数不变,但参数类型必须改变,返回值类型改变,功能也随之发生相应变化 其实质是将函数功能拓展

函数重载的方法与定义一个函数的方法几乎完全相同

格式为: 返回值类型 作用域::重载函数名 (参数表){函数定义}

注意:类其实也可以看做是一种数据类型 所以return 之后可以返回一个对象 (2)掌握使用虚函数实现动态多态性; 也叫动态联编 是通过指针实现的

练习项目

1.定义Point类,有坐标x,y两个成员变量,利用友元函数对Point类重载“++”运算符,实现对坐标值的改变。具体要求如下:

(3) 编写程序定义Point类,在类中定义整型的私有成员变量x,y; (4) 在类中定义两个友元函数,分别重载前置++和后置++; (5) 编写主函数测试。

注意函数有无返回值的区别,以及返回值是否带有&应用符号。

int a,b; 1程序代码:

#include a=c.x++; b=c.y++; //using namespace std; cout<<\//Powered by X.Duke return c; class Point{ } int x,y; void show() public: { Point(){} cout<<\ x=\ Point(int &a,int &b) } { x=a,y=b; } }; friend Point operator++(Point &c){ int a,b; int main(void) a=++c.x; b=++c.y; { cout<<\ cout<<\ return c; int a,b; } cin>>a;cin>>b; friend Point operator++(Point &c,int){ Point ob1(a,b);

26

}

cout<<\cout<<\ob1.show();

cout<<\cout<<\ob1.show(); return 0;

运行结果:

x,y 5 6

Point++-> x=5,y=6

Now Point -> x=6,y=7 ++Point-> x=7,y=8 Now Point-> x=7,y=8 Press any key to continue

2.定义Point类,有坐标x,y两个成员变量,利用运算符重载对Point类重载“++”运算符,实现对坐标值的改变。具体要求如下:

1) 编写程序定义Point类,在类中定义整型的私有成员变量x,y;

2) 定义成员函数Point& operator++(); Point operator++(int);以实现对Point类重载“++”运算符,分别重载前置++

和后置++;

3) 编写主函数测试。

{ cout<<\Point ->

2 程序代码: x=\#include }; using namespace std; int main(void) //Powered by X.Duke { class Point{ int a,b; int x,y; cout<<\public: cin>>a>>b; Point(){} Point obj(a,b); Point(int &a,int &b) obj++; { x=a; y=b; } obj.show(); Point operator++(int){ ++obj; int a,b; obj.show(); a=x++; b=y++; return 0; cout<<\} return *this;

运行结果: }

Point operator++(){ Input x y int a,b; 5 6 a=++x; b=++y; Point++ -> x=5,y=6 cout<<\Now Point -> x=6,y=7 return *this; ++Point -> x=7,y=8 } Now Point -> x=7,y=8 void show() Press any key to continue

3.定义一个分数类,通过重载运算符实现分数的四则运算、求负运算和赋值运算。其中,要求加法“+” 和减法“-”用友元函数实现重载,其他运算符用成员函数实现重载。

3程序代码:

27

#include #include //using namespace std; //Powered by X.Duke

void simple(int &a,int &b)//将分子分母化简 { int i,c; c=abs(a)0&&b<0){a=-a;b=-b;}// }

class number{ int x,y; public: number(int a,int b) {x=a; y=b; simple(x,y);} friend number operator+(number &a,number &b){ number temp(0,0); temp.y=a.y*b.y; //先通分 temp.x=a.x*b.y+b.x*a.y; //通分后分子相加 simple(temp.x,temp.y); //最后化简 return temp; } friend number operator-(number &a,number &b){ number temp(0,0); temp.y=b.y*a.y; //与加法相同 temp.x=a.x*b.y-b.x*a.y; simple(temp.x,temp.y); return temp; } number operator*(number &a) { x*=a.x; y*=a.y; simple(x,y); return *this; } number operator/(number &a)

28

{

x*=a.y; y*=a.x; simple(x,y); return *this; } number operator=(number& a) { x=a.x; y=a.y; simple(x,y); return *this; } number operator-()//单目运算符“-”重载 { x=-x; y=y; return *this; } void print() {cout<<\ };

int main(void) { int x,y; cout<<\Class a/b a=? b=?\ number a(x,y); a.print(); cout<<\ a=-a; a.print(); cout<<\a/b=x/y Now Input x=? y=?\ number *p=new number(x,y);//来个动态的玩玩 a=*p; a.print(); delete p; cout<<\a/b+x/y Now Input x=? y=?\ number *q=new number(x,y); a=a+*q; a.print(); delete q;

cout<<\a/b-x/y Now y=?\ number *r=new number(x,y); a=a-*r; a.print(); delete r; cout<<\(a/b)*(x/y) Now y=?\ number *s=new number(x,y); a=a*(*s); a.print(); delete s; cout<<\(a/b)/(x/y) Now y=?\ number *t=new number(x,y); a=a/(*t); a.print(); delete t; return 0; }

Input x=?

运行结果:

Building Class a/b a=? b=? 5 6

Now a/b=5/6 Run a/b=-a/b Now a/b=-5/6

Run a/b=x/y Now Input x=? y=? 7 8

Now a/b=7/8

Run a/b+x/y Now Input x=? y=? 9 8

Now a/b=2/1

Run a/b-x/y Now Input x=? y=? 14 15

Now a/b=16/15

Run (a/b)*(x/y) Now Input x=? y=? 3 4

Now a/b=4/5

Run (a/b)/(x/y) Now Input x=? y=? 4 5

Now a/b=1/1

Press any key to continue

Input x=?

Input x=?

4.定义一个车(vehicle)基类,有Run、Stop等成员函数,由此派生出自行车(bicycle)类、汽车(motorcar)类,从bicycle和motorcar派生出摩托车(motorcycle)类,它们都有Run、Stop等成员函数。具体要求如下: (1) 编写程序定义一个车(vehicle)基类,有Run、Stop等成员函数; (2) 由车(vehicle)基类派生出自行车(bicycle)类、汽车类(motorcar),从bicycle类和motorcar类派生出摩托

车类(motorcycle),它们都有Run、Stop等成员函数。

(3) 在main()函数中定义vehicle、bicycle、motorcar、motorcycle的对象,调用其Run()、Stop()函数,观察

其执行情况。

(4) 分别用vehicle类型的指针来调用几个对象的成员函数,看看能否成功(提示:把Run、Stop定义为虚

函数)。

class bicycle:virtual public vehicle{

4程序代码: public: #include void run() using namespace std; {cout<<\//Powered by X.Duke void stop() class vehicle{ {cout<<\public: }; virtual void run() class motorcar:virtual public vehicle{ {cout<<\public: virtual void stop() void run() {cout<<\ {cout<<\}; void stop()

29

{cout<<\ ptr=&m_c; }; ptr->run(); class motorcycle:public bicycle,public motorcar{ ptr->stop(); public: ptr=&m_cy; void run() ptr->run(); {cout<<\ ptr->stop(); void stop() return 0; {cout<<\} };

运行结果: int main(void)

{ Bicycle run vehicle *ptr; Bicycle stop motorcar m_c; Motorcar run bicycle b; Motorcar stop motorcycle m_cy; Motorcycle run ptr=&b; Motorcycle stop ptr->run(); Press any key to continue ptr->stop();

5.编写程序,定义抽象基类Container,由此派生出2个派生类球体类Sphere,圆柱体类Cylinder,分别用虚函数分别计算表面积和体积。

(1) 球体的表面积为:4?r2,球体的体积为

4?r3; 圆柱表面积为: 2πR(h+R) 圆柱3体的体积πR2h。

(2) 定义相应的对象,编写主函数测试。

5程序代码:

#include using namespace std; //Powered by X.Duke const double PI=3.14; class Containner{ public: Containner(double a) {r=a; } virtual void area()=0; virtual void volume()=0; protected: double r; };

class Sphere:public Containner{ public:

30

Sphere(double a):Containner(a) {} void area() {cout<<\ void volume() {cout<<\olume=\};

class Cylinder:public Containner{ public: Cylinder(double a,double b):Containner(a) {h=b; } void area() {cout<<\ void volume() {cout<<\private: double h;

本文来源:https://www.bwwdw.com/article/893r.html

Top