实验一: 类和对象的定义及使用

一、 实验目的和要求
(1)掌握类与对象的定义与使用方法,理解面向对象方法中通过对象间传递消息的工作机制。
(2)正确掌握类的不同属性成员的使用方法。
(3)掌握构造函数与析构函数的概念,理解构造函数与析构函数的执行过程。
(4)掌握友元函数和友元类的定义和使用。
(5)基本掌握指针和引用作为函数参数的应用。

二、实验环境(实验设备)
硬件: 微型计算机
软件: Windows 操作系统、Microsoft Visual Studio 2010

三、实验原理及内容
实验题目1 定义一个借书证类BookCard,在该类定义中包括如下内容。
(1)私有数据成员:
string id; //借书证学生的学号
string stuName; //借书证学生的姓名
int number; //所借书的数量
(2)公有成员函数:
构造函数 //用来初始化3 个数据成员,是否带默认参数值参考结果来分析
void display() //显示借书证的3 个数据成员的信息
bool borrow() //已借书数量不足10 则将数量加1,数量达到10 则直接返回false
主函数及f()函数代码如下。请结合输出结果完成程序。
void f(BookCard &bk)
{
if (!bk.borrow())
{
bk.display();
cout<<“you have borrowed 10 books,can not borrow any more!”<<endl;
}
else
bk.display();
}
int main()
{
BookCard bk1(“B20190620”,“东平”,10),bk2;
f(bk1);
f(bk2);
return 0;
}
程序的运行结果为:
B20190620 东平 10
you have borrowed 10 books,can not borrow any more!
B19010250 雪峰 4
参考实验教材中相应的实验指导,完成源程序代码如下:(中文五号宋体,英文五号Consolas字体,单倍行距)

#include<iostream>
#include<string>
using namespace std;
class BookCard{
private :
	string id;
	string stuName;
	int number;
public:
	BookCard(string i="B19010250",string stu="雪峰",int a=4);
	void display();
	bool borrow();
	
};

BookCard::BookCard(string i,string stu,int a):id(i),stuName(stu),number(a)
{}
void BookCard::display()
{
	cout<<id<<" "<<stuName<<" "<<number<<endl;
}
bool  BookCard::borrow()
{
	if(number==10)
		return 0;
	else if(number>0&&number<10)
		return 1;
}
void f(BookCard &bk)
{
	if(!bk.borrow())
	{
		bk.display();
		cout<<"you have borrowed 10 books,can not borrow any more!"<<endl;
	}
	else
		bk.display();
}

int main()
{
	BookCard bk1("B20190620","东平",10),bk2;
	f(bk1);
	f(bk2);
    return 0;
}

三、实验原理及内容
实验题目1 定义一个借书证类BookCard,在该类定义中包括如下内容。
(1)私有数据成员:
string id; //借书证学生的学号
string stuName; //借书证学生的姓名
int number; //所借书的数量
(2)公有成员函数:
构造函数 //用来初始化3 个数据成员,是否带默认参数值参考结果来分析
void display() //显示借书证的3 个数据成员的信息
bool borrow() //已借书数量不足10 则将数量加1,数量达到10 则直接返回false
主函数及f()函数代码如下。请结合输出结果完成程序。
void f(BookCard &bk)
{
if (!bk.borrow())
{
bk.display();
cout<<“you have borrowed 10 books,can not borrow any more!”<<endl;
}
else
bk.display();
}
int main()
{
BookCard bk1(“B20190620”,“东平”,10),bk2;
f(bk1);
f(bk2);
return 0;
}
程序的运行结果为:
B20190620 东平 10
you have borrowed 10 books,can not borrow any more!
B19010250 雪峰 4
参考实验教材中相应的实验指导,完成源程序代码如下:(中文五号宋体,英文五号Consolas字体,单倍行距)

#include
#include
using namespace std;
class BookCard{
private :
string id;
string stuName;
int number;
public:
BookCard(string i=“B19010250”,string stu=“雪峰”,int a=4);
void display();
bool borrow();

};

BookCard::BookCard(string i,string stu,int a):id(i),stuName(stu),number(a)
{}
void BookCard::display()
{
cout<<id<<" “<<stuName<<” "<<number<<endl;
}
bool BookCard::borrow()
{
if(number==10)
return 0;
else if(number>0&&number<10)
return 1;
}
void f(BookCard &bk)
{
if(!bk.borrow())
{
bk.display();
cout<<“you have borrowed 10 books,can not borrow any more!”<<endl;
}
else
bk.display();
}

int main()
{
BookCard bk1(“B20190620”,“东平”,10),bk2;
f(bk1);
f(bk2);
return 0;
}

实验题目2 定义一个时间类Time,有三个私有成员变量Hour、Minute、Second,定义构造函数、析构函数以及用于改变、获取、输出时间信息的公有函数,主函数中定义时间对象,并通过调用各种成员函数完成时间的设定、改变、获取、输出等功能。
① 按要求完成类的定义与实现。
② 修改数据成员的访问方式,观察编译结果。
③ 在Time类中定义一个成员函数,用于实现时间增加一秒的功能,主函数中通过对象调用该函数,并输出增加一秒后的时间信息。
④ 定义一个普通函数。
void f(Time t)
{ t. PrintTime( );
}
在Time类中增加拷贝构造函数的定义,主函数中调用该函数,运用调试工具跟踪,分析整个程序调用构造函数(包括拷贝构造函数)和析构函数的次数;再将f函数的形式参数分别修改为引用参数和指针参数(此时函数代码修改为{t-> PrintTime( );},主函数中调用,再分析此时调用构造函数和析构函数的次数。
参考实验教材中相应的实验指导完成程序,并回答相关问题。完成后的源程序代码如下:(中文五号宋体,英文五号Consolas字体,单倍行距)

#include<iostream>
using namespace std;
class Time
{
private:
	int Hour;
    int Minute;
    int Second;
public:
	Time(int h=0,int m=0,int n=0);
	Time(const Time &ob);
	~Time();
    void ChangeTime(int h,int m,int s);
    int GetHour();
    int GetMinute();
    int GetSecond();
    //void IncreaseOneSecond();
    void PrintTime();
};
Time::Time(int h,int m,int n)
{
	//cout<<"Constructing ..."<<endl;
	Hour=h;Minute=m;Second=n;
}
Time::Time(const Time &ob)
{
	//cout<<"Copy constructing..."<<endl;

}
Time::~Time()
{
	//cout<<"Destructing..."<<endl;
}
void Time::ChangeTime(int h ,int m,int s)
{
    Hour=h;Minute=m;Second=s;
}

int Time::GetHour()
{
    return Hour;
}

int Time::GetMinute()
{
    return Minute;
}

int Time::GetSecond()
{
    return Second;
}
void Time::PrintTime()
{
    cout<<Hour<<":"<<Minute<<":"<<Second<<endl;
}
/*void Time::IncreaseOneSecond()
{
   Second++;
   }*/
/*void f(Time t)
{  t.PrintTime();
   cout<<"call f\n";
 }*/
int main()
{
	Time t1;
	Time t2(6);
	Time t3(6,7);
	Time t4(6,7,8);
	t1.PrintTime();
	t2.PrintTime();
	t3.PrintTime();
	t4.PrintTime();
	t1.ChangeTime(11,12,13);
	t2.ChangeTime(11,12,13);
	t3.ChangeTime(11,12,13);
	t4.ChangeTime(11,12,13);
	cout<<t1.GetHour()<<":"<<t1.GetMinute()<<":"<<t1.GetSecond()<<endl;
	cout<<t2.GetHour()<<":"<<t2.GetMinute()<<":"<<t2.GetSecond()<<endl;
	cout<<t3.GetHour()<<":"<<t3.GetMinute()<<":"<<t3.GetSecond()<<endl;
	cout<<t4.GetHour()<<":"<<t4.GetMinute()<<":"<<t4.GetSecond()<<endl;
	return 0;
}

程序的运行结果是:

0:0:0
6:0:0
6:7:0
6:7:8
11:12:13
11:12:13
11:12:13
11:12:13

构造函数与析构函数的调用方式及执行顺序是:

调用方式是自动调用,执行顺序是先执行构造函数,待程序结束时再执行析构函数。
在任何情况下,析构函数的调用顺序与构造函数的调用顺序完全相反。

③取消类中成员函数IncreaceOneSecond( )的注释标志,将该函数补充完整,注意时间在增加一秒情况下的进位关系。
该函数的代码如下:(中文五号宋体,英文五号Consolas字体,单倍行距)

void Time::IncreaseOneSecond()
{
   if(Second<59)
	   Second++;
   else if(Second==59&&Minute==59&&Hour==23)
   {
	   Hour=0;
	   Minute=0;
	   Second=0;
   }
   else if(Second==59&&Minute==59&&Hour<23)
   {
	   Minute=0;
	   Second=0;
	   Hour++;
   }
   else if(Second==59&&Minute<59&&Hour<23)
   {
	   Minute++;
	   Second=0;
	   Hour++;
   }
   cout<<Hour<<":"<<Minute<<":"<<Second<<endl;
}

④ 主函数中定义一个Time类对象并调用一次f函数,观察结果填写下表:
f函数的原型 主函数中调用f的语句 构造函数调用次数 拷贝构造函数调用次数 析构函数调用次数
void f(Time t); f(t0) 1 1 2
void f(Time &t); f(t0) 1 0 1
void f(Time *t); f§ 1 0 1
通过以上结果,关于对象作形式参数、对象引用作形式参数、对象指针作形式参数时构造函数、析构函数的调用次数及顺序,你得到什么结论?

对象作为形式参数,调用之初把实参的值赋值给形参,函数体内形参的改变不会影响实际参数的值。
对象引用作为形式参数,相当于是实参的别名,实质上就是对实参对象进行操作,所以他会改变实参的值。
对象指针作形式参数,不调用拷贝构造函数,通过指针不仅可以访问实参对象的值,还可以进行修改,调用的时候要以地址形式给出。

实验题目3 定义一个Girl类和一个Boy类,这两个类中都有表示姓名、年龄的私有成员变量,都要定义构造函数、析构函数、输出成员变量信息的公有成员函数。
①根据要求定义相应的类。
②将Girl类作为Boy类的友元类,在Girl类的成员函数VisitBoy(Boy & )中访问Boy类的私有成员,观察程序运行结果。
③在Boy类的某成员函数VisitGirl(Girl & )中试图访问Girl类的私有成员,观察编译器给出的错误信息,理解原因。
④主函数中正确定义两个类的对象,调用各自的成员函数实现相应功能。
⑤再将Boy类作为Girl类的友元类,在Boy类的某成员函数VisitGirl(Girl & )中访问Girl类的私有成员,观察编译器给出的信息。
⑥删除两个类中的函数VisitGirl(Girl & ) ,VisitBoy(Boy & ),定义一个顶层函数VisitBoyGirl(Boy &, Girl &),作为以上两个类的友元,通过调用该函数输出男孩和女孩的信息。
实验解答:
①定义相应的类,主函数中定义相应的类成员,调用各类的输出函数显示信息。
源程序代码如下:

#include<iostream>
#include<string>
using namespace std;
class Boy;
class Girl
{
	string name;
	int age;
public:
	Girl(string N,int A);
	~Girl()
	{
		cout<<"Girl destructing...\n";
	}
	void Print();
	void VisitBoy(Boy & );
};
class Boy
{
	string name;
	int age;
	friend Girl;
public:
	Boy(string N,int A);
	~Boy()
	{
		cout<<"Boy destructing...\n";
	}
	void Print();
	void VisitGirl(Girl & );
};
Girl::Girl(string N,int A)
{
	name=N;
	age=A;
	cout<<"Girl constructing...\n";
}
void Girl::Print()
{
	cout<<"Girl's name: "<<name<<endl;
	cout<<"Girl's age: "<<age<<endl;
}
void Girl::VisitBoy(Boy &boy)
{
	cout<<"Boy's name: "<<boy.name<<endl;
	cout<<"Boy's age: "<<boy.age<<endl;
}
Boy::Boy(string N,int A)
{
	name=N;
	age=A;
	cout<<"Boy constructing...\n";
}
void Boy::Print()
{
	cout<<"Boy's name: "<<name<<endl;
	cout<<"Boy's age: "<<age<<endl;
}
/*void Boy::VisitGirl(Girl & girl)
{
	cout<<"Girl's name: "<<girl.name<<endl;
	cout<<"Girl's age: "<<girl.age<<end;
}*/
int main()
{
	Girl g("fang",20);
	Boy b("ming",19);
	g.VisitBoy(b);
	g.Print();
	b.Print();
	return 0;
}

程序的运行结果是:

Girl constructing…
Boy constructing…
Boy’s name: ming
Boy’s age: 19
Girl’s name: fang
Girl’s age: 20
Boy’s name: ming
Boy’s age: 19
Boy destructing…
Girl destructing…

②将Girl类作为Boy类的友元类, 写出Girl类的成员函数VisitBoy(Boy & )的实现代码。

void Girl::VisitBoy(Boy &boy)
{
	cout<<"Boy's name: "<<boy.name<<endl;
	cout<<"Boy's age: "<<boy.age<<endl;
}

程序的运行结果是:

Boy’s name: ming
Boy’s age: 19

③在Boy类的某成员函数VisitGirl(Girl & )中试图访问Girl类的私有成员,记录编译器给出的错误信息,与②对比,你能得出友元的什么特性?

友元关系是单向的,不具有交换性。

④在上面代码的基础上,在Girl类的定义中,增加一行代码:friend Boy; 在主函数中通过Boy类对象. VisitGirl(Girl类对象) 的形式输出Girl类对象的信息。编译的结果是什么?写出这一步你的主函数代码,要求分别用友元函数Girl类对象. VisitBoy(Boy类对象);和Boy类对象. VisitGirl(Girl类对象) ;和输出两个类对象的信息。

g.VisitBoy(b);
b.VisitGirl(g);
输出:
Girl constructing…
Boy constructing…
Boy’s name: ming
Boy’s age: 19
Girl’s name: fang
Girl’s age: 20
Girl’s name: fang
Girl’s age: 20
Boy’s name: ming
Boy’s age: 19
Boy destructing…
Girl destructing…

⑤定义一个顶层函数void VisitBoyGirl(Boy &, Girl &),作为以上两个类的友元函数,主函数中通过调用该函数输出男孩和女孩的信息。写出该友元函数的完整代码,以及主函数的代码。

void VisitBoyGirl(Boy &boy,Girl & girl)
{
	cout<<"Girl's name: "<<girl.name<<endl;
	cout<<"Girl's age: "<<girl.age<<endl;
	cout<<"Boy's name: "<<boy.name<<endl;
	cout<<"Boy's age: "<<boy.age<<endl;
}
VisitBoyGirl(b,g);

四、实验小结(包括问题和解决方法、心得体会、意见与建议等)
(中文五号宋体,英文五号Consolas字体,单倍行距)
(一)实验中遇到的主要问题及解决方法
1.在题目2中不改变main()函数中的对象的定义方式,若取消构造函数中参数的默认值,编译程序错误提示信息及出错原因是:
报错就不放辣
函数二义性
2.在题目2中如果删除类中自定义的构造函数,仅使用系统默认构造函数,再编译,程序错误提示信息及出错原因是:
报错就不放辣
构造函数实参不正确
3.在题目2中如果将main()函数中的输出语句改为:cout<<对象名.Hour<<":"<<对象名.Minute<<":"<<对象名.Second<<endl; 重新编译,会出现什么错误提示?在这种情况下,如果将成员变量的访问属性修改为public再编译,结果如何?
报错就不放辣
编译成功
4.其它问题及解决办法

“==”别写成 “=”

(二)实验心得

运用debug

(三)意见与建议(没有可省略)

五、支撑毕业要求指标点:
1.2-M掌握计算机软硬件相关工程基础知识,能将其用于分析信息安全领域的相关工程问题。
3.1-H掌握信息安全领域所涉及的软硬件系统,从数字电路、计算机系统、到各类系统软件的基本理论与设计结构。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐