实验四 数据的共享与保护
一、实验目的
1.掌握类的数据共享与保护的概念和使用方法
2.学习使用类的友元、静态成员,掌握多文件结构的程序编译预处理
二、实验内容
1、设计一个Grade类,判定学生某个考试的级别,全部操作在类Grade中实现(30分)。
要求:
(1)在定义对象时指定学生姓名和分数。且姓名必须指定,分数可缺省,缺省值为0分。要求包含构造函数、复制构造函数、姓名用string类型来定义。
主函数中实例化6个学生对象的姓名和分数分别为:
Sun l00
Wu 90
Jiang 52
Zhou 0
He 76
Liu 88
(2) 编写一个私有成员函数getGrade(),判定学生成绩的等级(60分以下为E等,[60-70)分为D等,[70-80)为C等,[80-90)为B等,[90-100]分为A等)。
(3)编写一个常成员函数getInfo()输出结果,包含学生姓名、分数、等级。
(4)定义静态数据成员count,用于统计总的学生人数,并在主函数中输出。
(5)定义该类的友元函数compare(Grade &m,Grade &n),比较两个学生成绩的高低,输出成绩高的那个学生信息。
2、请改写课本例题4-4线段(Line类),建立工程,使用多文件的组织结构实现程序(30分)。要求:
(1)文件划分:类定义文件(.h),类实现文件(.cpp),类使用文件(,cpp,主函数文件)。
(2)每个类的设计单独放在1个(.h)文件中,工程共包括5个文件。
(3)使用条件编译指令以免文件多次包含的情况。
(4)在Dev C++或VC中建立工程:文件-新建-项-(Basic—EmptyProject—C++项目)-新建文件夹Line,项目名称为Line,将所有文件保存在名为Line的文件夹中。VC建立过程是:文件—>新建—>工程—>Win32 Console Application。
3、请使用网页工具draw.io或其它或绘制UML图的工具创建一个UML图来描述上一题目中Line类与Point类的关系。(10分)
4、定义Boat和Car两个类,二者都有weight属性,定义二者的一个友元函数getTotalWeight()计算二者重量之和。(10分)
5、定义一个日期类(Date)和一个时间类(Time)。Time类是Date类的友元。Time类中的有打印时间的成员函数void display()可以实现打印出当前的时间,例如格式为:2021年10月30日;请编写程序设计这两个类,要求创建时间对象Today,并一次输出其中的日期和时间。(20分) 参考文献:C++关于时间操作 https://www.runoob.com/cplusplus/cpp-date-time.html
三、实验步骤及结果
题目1:
解题思路:
1.分数缺省可以在构造函数中给参数默认值0
2.判断等级可以用多重if嵌套
3.常成员函数注意const
4.统计总的人数 count应该在构造函数++和析构函数中–操作
5.比较成绩高低用if语句即可,调用getInfo输出信息
程序代码:
/*
程序名:题目1.cpp
功能:设计一个Grade类,判定学生某个考试的级别,全部操作在类Grade中 实现(30分)。要求:
(1)在定义对象时指定学生姓名和分数。且姓名必须指定,分数可缺省,缺省值为0分。要求包含构造函数、复制构造函数、姓名用string类型来定义。
主函数中实例化6个学生对象的姓名和分数分别为:
Sun l00
Wu 90
Jiang 52
Zhou 0
He 76
Liu 88
(2) 编写一个私有成员函数getGrade(),判定学生成绩的等级(60分以下为E等,[60-70)分为D等,[70-80)为C等,[80-90)为B等,[90-100]分为A等)。
(3)编写一个常成员函数getInfo()输出结果,包含学生姓名、分数、等级。
(4)定义静态数据成员count,用于统计总的学生人数,并在主函数中输出。
(5)定义该类的友元函数compare(Grade &m,Grade &n),比较两个学生成绩的高低,输出成绩高的那个学生信息。
日期:2021.11.15
版本:1.0
*/
#include <iostream>
#include <string>
using namespace std;
class Grade//Grade 类定义
{
private://私有数据成员
static int count;//静态数据成员声明,用于记录学生人数
string name;//学生姓名
int score;//分数
char grade;//等级
void getGrade(Grade &p);//判断学生等级
public://外部接口
Grade(string name,int score=0);//构造函数 分数缺省值为0
Grade(Grade &p);//复制构造函数
void getInfo(Grade &p) const;
friend void compare(Grade &m, Grade &n);//比较成绩的友元函数声明
static void showcount();//输出目前人数
};
int Grade::count = 0;//静态数据成员定义和初始化,使用类名限定
Grade::Grade(string N,int S) :score(0)//构造函数的实现
{
name = N;
score = S;
count++;
}
Grade::Grade(Grade &p)//复制构造函数的实现
{
name = p.name;
score = p.score;
count++;
}
void Grade::getGrade(Grade &p)//判断学生等级
{
if (p.score > 0 && p.score < 60)
p.grade = 'E';
else if (p.score >= 60 && p.score < 70)
p.grade = 'D';
else if (p.score >= 70 && p.score < 80)
p.grade = 'C';
else if (p.score >= 80 && p.score < 90)
p.grade = 'B';
else if (p.score >= 90 && p.score <= 100)
p.grade = 'A';
}
void Grade::getInfo(Grade &p) const//常成员函数的实现
{
cout << "姓名:" << p.name << endl;
cout << "分数:" << p.score << endl;
p.getGrade(p);
cout << "等级:" << p.grade << endl;
}
void compare(Grade &m, Grade &n)//友元函数实现
{
cout << "*******************************" <<endl;
cout << "两个比较的学生姓名为:" << m.name << " " << n.name << endl;
if (m.score > n.score)
{
cout << "成绩高的学生信息为:" << endl;
m.getInfo(m);
}
else
{
cout << "成绩高的学生信息为:" << endl;
n.getInfo(n);
}
}
void Grade::showcount()//输出目前人数
{
cout << "目前总的人数为:" << count << endl;
}
int main()
{
Grade p1("Sun", 100);
Grade p2("Wu", 90);
Grade p3("Jiang", 52);
Grade p4("Zhou");//分数缺省 默认为0
Grade p5("He", 76);
Grade p6("Liu", 88);
Grade::showcount();
compare(p1, p2);
compare(p2, p3);
compare(p4, p6);
system("pause");
return 0;
}
运行结果截图:
题目2:
解题思路:
1.将项目划分成三个部分:类定义文件(.h)、类实现文件(.cpp)、类的使用文件(*.cpp,主函数文件)
由于该项目有两个类 因此一共需要5个文件
2.注意编译预处理
使用条件编译指令和defined操作符来防止对类Point的重复定义
程序代码:
//文件1,Point类的定义,Point.h
#ifndef POINT_H
#define POINT_H
class Point//Point 类定义
{
public://外部接口
Point(int xx=0,int yy=0){
x=xx;
y=yy;
};//构造函数
Point(Point &p);//复制构造函数
int getX(){return x;}
int getY(){return y;}
private://私有数据成员
int x,y;
};
#endif
//文件2,Point类的实现,Point.cpp
#include "Point.h"
#include <iostream>
using namespace std;
Point::Point(Point &p){//复制构造函数的实现
x=p.x;
y=p.y;
cout << "Calling the copy constructor of Point" << endl;
}
//文件3,Line类的定义,Line.h
#include "Point.h"
#ifndef LINE_H
#define LINE_H
class Line{//Line 类定义
public://外部接口
Line(Point xp1,Point xp2);//构造函数
Line(Line &l);//复制构造函数
double getLen(){return len;}
private://私有数据成员
Point p1,p2;//Point类的对象p1,p2
double len;
};
#endif
//文件4,Line类的实现,Line.cpp
#include "Line.h"
#include "Point.h"
#include <iostream>
#include <cmath>
using namespace std;
//组合类的构造函数
Line::Line(Point xp1,Point xp2):p1(xp1),p2(xp2) {
cout << "Calling constructor of Line" <<endl;
double x=static_cast<double>(p1.getX()-p2.getX());
double y=static_cast<double>(p1.getY()-p2.getY());
len=sqrt(x*x+y*y);
}
//组合类的复制构造函数
Line::Line(Line &l):p1(l.p1),p2(l.p2){
cout << "Calling the copy constructor of Line" << endl;
len=l.len;
}
//文件5,主函数,题目2.cpp
/*
程序名:题目1.cpp
功能:请改写课本例题4-4线段(Line类),建立工程,使用多文件的组织结构实现程序(30分)。要求:
(1)文件划分:类定义文件(*.h),类实现文件(*.cpp),类使用文件(,cpp,主函数文件)。
(2)每个类的设计单独放在1个(.h)文件中,工程共包括5个文件。
(3)使用条件编译指令以免文件多次包含的情况。
(4)在Dev C++或VC中建立工程:文件-新建-项-(Basic—EmptyProject—C++项目)-新建文件夹Line
项目名称为Line,将所有文件保存在名为Line的文件夹中。
VC建立过程是:文件—>新建—>工程—>Win32 Console Application。
日期:2021.11.15
版本:1.0
*/
#include "Point.h"
#include "Line.h"
#include <iostream>
using namespace std;
int main(){
Point myp1(1,1),myp2(4,5);//建立Point类的对象
Line line(myp1,myp2);//建立Line类的对象
Line line2(line);//利用复制构造函数建立一个新对象
cout << "The length of the line is:";
cout << line.getLen() << endl;
cout << "The length of the line2 is:";
cout << line2.getLen() << endl;
return 0;
}
运行结果截图:
题目3:
解题思路:
Line类的数据成员包括了Point类的两个对象p1和p2,因此重数为2,而Point类的对象是Line类对象的一部分,因此需要应用聚集关系来描述。
另外,Line类的构造函数使用了Point类对象p1和p2的共有函数,可以简洁直观地将这种使用关系通过简单的依赖关系来描述
最后用带有褶角的矩形表示注释
问题:
请使用网页工具draw.io或其它或绘制UML图的工具创建一个UML图来描述上一题目中Line类与Point类的关系。
答案:
题目4:
解题思路:
题目比较简单,注意调用未定义的类之前需要前项引用声明
程序代码:
/*
程序名:题目4.cpp
功能:定义Boat和Car两个类,二者都有weight属性,定义二者的一个友元函数getTotalWeight()计算二者重量之和。(10分)
日期:2021.11.16
版本:1.0
*/
#include <iostream>
using namespace std;
class Car;//前项引用声明
class Boat//Boat类的定义
{
private://私有数据成员
int weight;
public://外部接口
Boat(int w){weight=w;} //构造函数
friend void getTotalWeight(Boat &b,Car &c); //友元函数
};
class Car//Car类的定义
{
private://私有数据成员
int weight;
public://外部接口
Car(int w){weight=w;}//构造函数
friend void getTotalWeight(Boat &b,Car &c); //友元函数
};
void getTotalWeight(Boat &b,Car &c)//友元函数实现
{
cout<< b.weight << " & " << c.weight <<endl ;
int TotalWeight=b.weight+c.weight;
cout << "两者体重之和为:" << TotalWeight << endl;
}
int main(){
Boat b(4);
Car c(6);
getTotalWeight(b,c);//调用函数计算总重
system("pause");
return 0;
}
运行结果截图:
题目5:
解题思路:
1.可以通过组合类来吧时间和日期连接起来 其中函数display使用了函数重载
2.输出当前系统时间:调用文献中
C 库函数 size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr)根据 format 中定义的格式化规则,格式化结构 timeptr 表示的时间,并把它存储在 str 中。
和C 库函数 struct tm *localtime(const time_t *timer) 使用 timer 的值来填充 tm 结构。timer 的值被分解为 tm 结构,并用本地时区表示。
注意加ctime头文件
3.输出当前时间(即对象的时间):
用cout即可实现
程序代码:
/*
程序名:题目5.cpp
功能:定义一个日期类(Date)和一个时间类(Time)。Time类是Date类的友元。
Time类中的有打印时间的成员函数void display()可以实现打印出当前的时间,例如格式为:2021年10月30日;
请编写程序设计这两个类,要求创建时间对象Today,并一次输出其中的日期和时间。(20分)
参考文献:C++关于时间操作 https://www.runoob.com/cplusplus/cpp-date-time.html
日期:2021.11.16
版本:1.0
*/
#include <iostream>
#include <ctime>
using namespace std;
class Date//Date类的定义
{
private://私有数据成员
int year;
int month;
int day;
public://外部接口
Date(int y,int m,int d)
{
year=y;
month=m;
day=d;
}
friend class Time;//Time类是Date类的友元类
};
class Time{//Time类的定义
private://私有数据成员
int hour;
int minute;
int second;
Date date;
public://外部接口
Time(int h,int m,int s,Date D):hour(h),minute(m),second(s),date(D) {}//构造函数
void display();//显示系统时间
void display(Time t);//显示时间
};;
void Time::display()//显示系统时间
{
time_t rawtime;
struct tm *info;
char buffer[80];
time( &rawtime );
info = localtime( &rawtime );
strftime(buffer, 80, "%Y年%m月%d日 %H:%M:%S", info);//调用strftime函数 参考题目中文献获得 需要头文件ctime
cout << " 系统时间为: " << buffer << endl;
}
void Time::display(Time t){//显示时间
cout << "你创建的时间为:"<< t.date.year <<"年"<< t.date.month <<"月"<< t.date.day <<"日 "
<< t.hour <<":"<< t.minute <<":"<< t.second <<endl;
}
int main(){
Date d(2003,4,9);
Time t(20,20,20,d);
t.display(t);//调用函数显示时间
t.display();//调用函数显示系统时间
system("pause");
return 0;
}
运行结果截图:
四、实验小结
问题与解决办法:
1.问题:
函数实现显示undefined reference
解决方法:忘记了加类的作用域::
2.问题:
[Error] ISO C++ forbids in-class initialization of non-const static member ‘Grade::count’
解决方法:类的静态数据成员必须在类外进行定义和初始化,使用类名限定
3.问题:
想要给某个参数缺省值,通过构造函数初始化去进行却没有实现
解决方法:参数缺省应该在参数列表中初始化,或者再定义一个默认构造函数
心得体会:
碰到新知识不会,比方说这次实验报告中的时间操作,光看文献根本看不懂,可以通过找相关题目的代码来帮助学习
有时候看文字看不懂,但是看代码调试运行一遍就能够学会其中的知识点。
长代码报错很正常,学会单步调试慢慢去改。