《C++语言基础》实践项目——深复制、友元、模板

来源:互联网 发布:文艺有内涵的网名知乎 编辑:程序博客网 时间:2024/06/15 21:46

返回:贺老师课程教学链接


【项目1-深复制体验】
(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;}
[参考解答]

0 0