返回:贺老师课程教学链接
【项目1-深复制体验】
(1)阅读下面的程序,补足未完成的注释
(2)将注释(a)所在的那一行去掉,会出现什么现象?为什么?为什么a数据成员所占用的存储空间要在aa长度基础上加1?若指针a不是指向字符(即不作为字符串的地址),是否有必要加1?
(3)为类A增加复制构造函数,用下面的main函数测试
【项目2-我的数组类】
下面的程序,因为存在指针类型的数据成员,需要能完成深复制的构造函数。请补充完整构造函数和析构函数(其他不必动)。其中,构造函数要完成下面三个任务:
(1)为各成员函数赋值,按照深复制原则,其中arrayAddr应该是为保存数据新分配的连续空间的首地址;
(2)MyArray(int *a, int n)中,要将a指向的数组中的数值,逐个地复制到新分配的arrayAddr指向的空间中;
(3)getMax( )函数采取的策略是直接返回max(所以,计算max的工作,由构造函数完成)
(1)阅读下面的程序,补足未完成的注释
#include<iostream> #include<cstring> using namespace std; class A { private: char *a; public: A(char *aa) { a = new char[strlen(aa)+1]; //(a)这样处理的意义在于:______________________________ strcpy(a, aa); //(b)数据成员a与形式参数aa的关系:___________________________________ } ~A() { delete []a; //(c)这样处理的意义在于: ___________________________________________ } void output() { cout<<a<<endl; } }; int main(){ A a("good morning, code monkeys!"); a.output(); A b("good afternoon, codes!"); b.output(); return 0; }
(2)将注释(a)所在的那一行去掉,会出现什么现象?为什么?为什么a数据成员所占用的存储空间要在aa长度基础上加1?若指针a不是指向字符(即不作为字符串的地址),是否有必要加1?
(3)为类A增加复制构造函数,用下面的main函数测试
int main() { A a("good morning, code monkeys!"); a.output(); A b(a); b.output(); return 0; }[ 参考解答]
【项目2-我的数组类】
下面的程序,因为存在指针类型的数据成员,需要能完成深复制的构造函数。请补充完整构造函数和析构函数(其他不必动)。其中,构造函数要完成下面三个任务:
(1)为各成员函数赋值,按照深复制原则,其中arrayAddr应该是为保存数据新分配的连续空间的首地址;
(2)MyArray(int *a, int n)中,要将a指向的数组中的数值,逐个地复制到新分配的arrayAddr指向的空间中;
(3)getMax( )函数采取的策略是直接返回max(所以,计算max的工作,由构造函数完成)
#include<iostream> using namespace std; class MyArray { private: int *arrayAddr; //保存一个有len个整型元素的数组的首地址 int len; //记录动态数组的长度 int max; //动态数组中的最大值(并非动态数组中必须要的数据成员) public: MyArray(int *a, int n); ~MyArray(); int getValue(int i); //获得数组中下标为i的元素的值 int getLen(); //返回数组长度 int getMax( ); //返回数组中的最大值 }; int MyArray::getValue(int i){ //获得数组中下标为i的元素的值 return arrayAddr[i]; } int MyArray::getLen(){ //返回数组长度 return len; } int MyArray::getMax( ) { //返回数组中的最大值 return max; } int main(){ int b[10]= {75, 99, 90, 93, 38, 15, 5, 7, 52, 4}; MyArray r1(b,10); cout<<"最大值:"<<r1.getMax()<<endl; int c[15] = {18,68,10,52,3,19,12,100,56,96,95,97,1,4,93}; MyArray r2(c,15); int i,s=0; for(i=0; i<r2.getLen(); i++) s+=r2.getValue(i); cout<<"所有元素的和为:"<<s<<endl; return 0; }[ 参考解答]
【项目3-人数不定的工资类】
设计一个工资类(Salary),其中的数据成员包括职工人数(number,人数不定)和number个职工的工资salary,要求输入职工工资并逐个输出。
提示:用固定大小的数组存储number个职工的工资,可能造成空间的浪费,也可能会由于空间不够而不能处理职工人数过多的应用。将salary声明为指针类型的成员,通过动态分配空间,分配正好大小的空间存储数据。
class Salary { public: Salary(int n); //n为职工人数,初始化时完成空间的分配 ~Salary(); //析构函数中释放初始化时分配的空间 void input_salary(); void show_salary(); private: double *salary; int number; }; //下面定义类的成员函数 …… //下面是测试函数 int main() { Salary s(10); s.input_salary(); s.show_salary(); return 0; }[ 参考解答]
【项目4-成员函数、友元函数和一般函数有区别】
(1)阅读下面的程序,体会注释中的说明。
//例:使用成员函数、友元函数和一般函数的区别 #include <iostream> using namespace std; class Time { public: Time(int h,int m,int s):hour(h),minute(m),sec(s) {} void display1(); //display1是成员函数 friend void display2(Time &); //display2是友元函数 int getHour(){return hour;} int getMinute(){return minute;} int getSec(){return sec;} private: int hour; int minute; int sec; }; void Time::display1() //成员函数display1的实现,dispaly1前加Time:: { //以hour形式直接访问私有数据成员,实质是this->hour形式 cout<<hour<<":"<<minute<<":"<<sec<<endl; } void display2(Time &t) //友元函数dispaly2的实现,不加Time::,友元并不是类的成员 { //虽然不是类的成员函数,却可以用t.hour的形式直接访问私有数据成员——这就是友元 cout<<t.hour<<":"<<t.minute<<":"<<t.sec<<endl; } void display3(Time &t) //display3是一般函数,dispaly3前不加Time:: { //不能直接访问,只能用公共接口t.getHour()形式访问私有数据成员 cout<<t.getHour()<<":"<<t.getMinute()<<":"<<t.getSec()<<endl; } int main() { Time t1(10,13,56); t1.display1(); //成员函数这样调用:对象名.函数名() display2(t1); //友员函数的调用和一般函数无异(但实现中可以不同) display3(t1); //一般函数的调用 return 0; }(2)模仿上面的示例,完成求点类中距离的任务。你需要实现求距离函数的三种版本:分别利用成员函数、友元函数和一般函数求两点间距离的函数,并设计main()函数完成测试。
提示:此项目和例子的区别在于“距离是一个点和另外一个点的距离”,不同版本在参数上有体现。三个版本建议分开测试,也可以如示例,放在一个程序中完成。
下面是点类的部分代码。
class CPoint { private: double x; // 横坐标 double y; // 纵坐标 public: CPoint(double xx=0,double yy=0):x(xx),y(yy){} ……//请继续写需要的代码 };[ 参考解答]
【项目5-友元类】
定义下面两个类的成员函数(为体验友元类,实际上本例并不一定是一个好的设计,将两个类的合并为一个DateTime,日期、时间都处理更好)
class Date; //对Date类的提前引用声明 class Time { public: Time(int,int,int); void add_a_second(Date &); //增加1秒,1秒后可能会到了下一天,乃到下一月、下一年 void display(Date &); //显示时间,格式:月/日/年 时:分:秒 private: int hour; int minute; int sec; }; class Date { public: Date(int,int,int); friend class Time; //Time为Date的友元类 private: int month; int day; int year; }; int main( ) { Time t1(23,59,32); Date d1(12,31,2013); //测试时,再试试Date d1(2,28,2013)会如何 for(int i=0; i<=100; i++) { t1.add_a_second(d1); t1.display(d1); } return 0; } //下面定义两个类中的成员函数,要求不得再增加成员函数 //注意体会在Time的成员函数中可以调用Date类的私有数据成员[ 参考解答]
【项目6-复数模板类】
阅读教材例10.1。该例实现了一个复数类,但是美中不足的是,复数类的实部和虚部都固定只能是double型的。可以通过模板类的技术手段,设计Complex,使实部和虚部的类型为定义对象时指定的实际类型。
(1)要求类成员函数在类外定义。
(2)在此基础上,再实现减法、乘法和除法
你可以使用的main()函数如下。
int main( ) { Complex<int> c1(3,4),c2(5,-10),c3; //实部和虚部是int型 c3=c1.complex_add(c2); cout<<"c1+c2="; c3.display( ); Complex<double> c4(3.1,4.4),c5(5.34,-10.21),c6; //实部和虚部是double型 c6=c4.complex_add(c5); cout<<"c4+c5="; c6.display( ); //下面测试减法、乘法和除法 …… return 0; }
(3)友元函数提供了一种非成员函数访问私有数据成员的途径,模板类使类中的数据成员的类型变得灵活,这两种技术可以结合起来用。要求在前面方案的基础上支持用友员函数实现的加法。用于测试的main()函数如下:
int main( ) { Complex<int> c1(3,4),c2(5,-10),c3; c3=c1.complex_add(c2); //调用成员函数支持加法运算,有一个形参 cout<<"c1+c2="; c3.display( ); Complex<double> c4(3.1,4.4),c5(5.34,-10.21),c6; c6=c4.complex_add(c5); //调用成员函数支持加法运算,有一个形参 cout<<"c4+c5="; c6.display( ); Complex<int> c7; c7=add_complex(c1,c2); //调用友员函数支持加法运算,有两个形参 cout<<"c1+c2="; c7.display( ); Complex<double> c8; c8=add_complex(c4,c5); //调用友员函数支持加法运算,有两个形参 cout<<"c4+c5="; c8.display( ); return 0; }[ 参考解答]