实 验 报 告 | |||||||||||||||||||||||
实验名称 | 类和对象的定义及使用 | ||||||||||||||||||||||
实验类型 | 验证 | 实验学时 | 2 | ||||||||||||||||||||
(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 id,string stuName,int number); void display(); bool borrow(); }; BookCard::BookCard(string i="B19010250",string na="雪峰",int n=4) { id=i;stuName=na;number=n; } void BookCard::display() { cout<<id<<" "<<stuName<<" "<<number<<endl; } bool BookCard::borrow() { if(number<10&&number>0) return 1; else return 0; } 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 s=0); Time(const Time &ob); ~Time(); void change(int h,int m,int s); int GetHour(); int GetMinute(); int GetSecond(); void PrintTime(); //void IncreaseOneSecond(); }; Time::Time(int h,int m,int s) { //cout<<"Constructing..."<<endl; Hour=h;Minute=m;Second=s; } Time::Time(const Time &ob) { //cout<<"Copy constructing..."<<endl; } Time::~Time() { //cout<<"Destructing..."<<endl; } void Time::change(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<<"h"<<Minute<<"min"<<Second<<"s"<<endl; } /*void Time::IncreaseOneSecond() { Second++; }*/ /*void f(Time t) { t. PrintTime( ); } */ int main() { int h,m,s; Time t1; Time t2(6); Time t3(6,7); Time t4(6,7,8); t1.PrintTime(); t2.PrintTime(); t3.PrintTime(); t4.PrintTime(); t1.change(11,12,13); t2.change(11,12,13); t3.change(11,12,13); t4.change(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; } 程序的运行结果是: 0h0min0s 6h0min0s 6h7min0s 6h7min8s 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函数,观察结果填写下表:
通过以上结果,关于对象作形式参数、对象引用作形式参数、对象指针作形式参数时构造函数、析构函数的调用次数及顺序,你得到什么结论? 实验题目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{ private: string name; int age; public: Girl(string n,int a); ~Girl() { cout<<"Girl destructing..."<<endl; } void print(); void VisitBoy(Boy &); }; class Boy{ private: string name; int age; //friend Girl; public: Boy(string n,int a); ~Boy() { cout<<"Boy destructing..."<<endl; } void print(); void VisitGirl(Girl &); }; Girl::Girl(string n,int a) { name=n; age=a; cout<<"Girl constructing..."<<endl; } void Girl::print() { cout<<"Girl's name:"<<name<<" age:"<<age<<endl; } void Girl::VisitBoy(Boy &boy) { cout<<"Boy's name:"<<name<<" age:"<<age<<endl; } Boy::Boy(string n,int a) { name=n;age=a; cout<<"Boy constructing..."<<endl; } void Boy::print() { cout<<"Boy's name:"<<name<<" age:"<<age<<endl; } void Boy::VisitGirl(Girl &girl) { cout<<"Girl's name:"<<name<<" age:"<<age<<endl; } int main() { Girl a("fang",20); Boy b("zhou",20); a.VisitBoy(b); a.print(); b.print(); } 程序的运行结果是: Girl constructing... Boy constructing... Boy's name:fang age:20 Girl's name:fang age:20 Boy's name:zhou age:20 Boy destructing... Girl destructing... ②将Girl类作为Boy类的友元类, 写出Girl类的成员函数VisitBoy(Boy & )的实现代码。 void Girl::VisitBoy(Boy &boy) { cout<<"Boy's name:"<<name<<" age:"<<age<<endl; } 程序的运行结果是: Boy's name:zhou age:20 ③在Boy类的某成员函数VisitGirl(Girl & )中试图访问Girl类的私有成员,记录编译器给出的错误信息,与②对比,你能得出友元的什么特性? 友元关系是单向的,不具有交换性,只有两个类都将对方声明为自己的友元才可互访。 ④在上面代码的基础上,在Girl类的定义中,增加一行代码:friend Boy; 在主函数中通过Boy类对象. VisitGirl(Girl类对象) 的形式输出Girl类对象的信息。编译的结果是什么?写出这一步你的主函数代码,要求分别用友元函数Girl类对象. VisitBoy(Boy类对象);和Boy类对象. VisitGirl(Girl类对象) ;和输出两个类对象的信息。 a.VisitBoy(b); b.VisitGirl(a); a.print(); b.print(); Girl constructing... Boy constructing... Boy's name:fang age:20 Girl's name:zhou age:20 Girl's name:fang age:20 Boy's name:zhou age:20 Boy destructing... Girl destructing... ⑤定义一个顶层函数void VisitBoyGirl(Boy &, Girl &),作为以上两个类的友元函数,主函数中通过调用该函数输出男孩和女孩的信息。写出该友元函数的完整代码,以及主函数的代码。 void VisitBoyGirl(Boy &boy, Girl &girl) { cout<<"Boy's name:"<<name<<" age:"<<age<<endl; cout<<"Girl's name:"<<name<<" age:"<<age<<endl; } VisitBoyGirl(b,a); 四、实验小结(包括问题和解决方法、心得体会、意见与建议等) (中文五号宋体,英文五号Consolas字体,单倍行距) (一)实验中遇到的主要问题及解决方法 1.在题目2中不改变main()函数中的对象的定义方式,若取消构造函数中参数的默认值,编译程序错误提示信息及出错原因是: error C2512: 'Time' : no appropriate default constructor available 函数二义性 2.在题目2中如果删除类中自定义的构造函数,仅使用系统默认构造函数,再编译,程序错误提示信息及出错原因是: error C2512: 'Time' : no appropriate default constructor available 构造函数实参不正确 3.在题目2中如果将main()函数中的输出语句改为:cout<<对象名.Hour<<":"<<对象名.Minute<<":"<<对象名.Second<<endl; 重新编译,会出现什么错误提示?在这种情况下,如果将成员变量的访问属性修改为public再编译,结果如何? error C2248: 'Time::Hour' : cannot access private member declared in class 'Time' 编译成功 4.其它问题及解决办法 程序有点长,可以打草稿 (二)实验心得 多敲代码 (三)意见与建议(没有可省略) 建议多敲代码,注意区分析构函数和构造函数,注意无参和有参函数的区别 |
南京邮电大学C++实验报告1
最新推荐文章于 2024-05-28 09:35:56 发布