《C++primerplus》第11章练习题

 1.修改程序清单11.5(随机漫步),使之以特定的格式将结果写入文件中。

//vector.h -- Vector Class
#ifndef _VECTOR_H_
#define _VECTOR_H_
#include<iostream>
#include<fstream>
namespace VECTOR
{
    class Vector
    {
    public:
        enum Mode{RECT,POL};

    private:
        double x;
        double y;
        double mag;
        double ang;
        Mode mode;
    //private methods for setting values
        void set_mag();
        void set_ang();
        void set_x();
        void set_y();

    public:
        Vector();
        Vector(double n1, double n2, Mode form = RECT);
        void reset(double n1, double n2, Mode form = RECT);
        ~Vector();
        double xval() const { return x; }
        double yval() const { return y; }
        double magval() const { return mag; }
        double angval() const { return ang; }
        void polar_mode();
        void rect_mode();
    //operator overloading
        Vector operator + (const Vector & b)const;
        Vector operator - (const Vector & b)const;
        Vector operator - ()const;
        Vector operator *(double n) const;
    //friends
        friend Vector operator*(double n, Vector & a);
        friend std::ostream & operator<<(std::ostream & os, const Vector & v);
        friend std::ofstream & operator<<(std::ofstream & ofs, const Vector & v);
    };
}    //end namespace VECTOR

#endif // VECTOR_H_INCLUDED
//vector.cpp -- Methods for Vector class
#include <cmath>
#include "vector.h"

using std::sqrt;
using std::sin;
using std::cos;
using std::atan;
using std::atan2;
using std::cout;

namespace VECTOR
{
    const double Rad_to_deg = 45.0 / atan(1.0);

    //private methods
    void Vector::set_mag()
    {
        mag = sqrt(x*x + y * y);
    }

    void Vector::set_ang()
    {
        if (x == 0.0 && y == 0.0)
        {
            ang = 0.0;
        }
        else
        {
            ang = atan2(y, x);
        }
    }

    void Vector::set_x()
    {
        x = mag * cos(ang);
    }

    void Vector::set_y()
    {
        y = mag * sin(ang);
    }

    //public methods
    Vector::Vector()
    {
        x = y = mag = ang = 0.0;
        mode = RECT;
    }

    //construct vector from rectangular or polar coordinate
    Vector::Vector(double n1, double n2, Mode form)
    {
        mode = form;
        if (form == RECT)
        {
            x = n1;
            y = n2;
            set_mag();
            set_ang();
        }
        else if (form == POL)
        {
            mag = n1;
            ang = n2 / Rad_to_deg;
            set_x();
            set_y();
        }
        else
        {
            cout << "Incorrect 3rd argument to Vector() -- ";
            cout << "Vector set to 0\n";
            x = y = mag = ang = 0;
            mode = RECT;
        }
    }

    void Vector::reset(double n1, double n2, Mode form)
    {
        mode = form;
        if (form == RECT)
        {
            x = n1;
            y = n2;
            set_mag();
            set_ang();
        }
        else if (form == POL)
        {
            mag = n1;
            ang = n2 / Rad_to_deg;
            set_x();
            set_y();
        }
        else
        {
            cout << "Incorrect 3rd argument to Vector() -- ";
            cout << "Vector set to 0\n";
            x = y = mag = ang = 0;
            mode = RECT;
        }
    }

    Vector::~Vector()
    {
    }

    void Vector::rect_mode()
    {
        mode = RECT;
    }

    void Vector::polar_mode()
    {
        mode = POL;
    }

    Vector Vector::operator + (const Vector & b)const
    {
        return Vector(x + b.x,y + b.y);
    }

    Vector Vector::operator - (const Vector & b )const
    {
        return Vector(x - b.x,y - b.y);
    }

    Vector Vector::operator - ()const
    {
        return Vector(-x,-y);
    }

    Vector Vector::operator * (double n)const
    {
        return Vector(n*x,n*y);
    }

    Vector operator * (double n,const Vector & a)
    {
        return a * n;
    }

    //display coordinates
    std::ostream & operator <<(std::ostream & os, const Vector &v)
    {
        if(v.mode == Vector::RECT)
            os<<"(x,y) = ("<<v.x<<","<<v.y<<")";
        else if(v.mode == Vector::POL)
        {
            os<<"(m,a) = ("<<v.mag<<","<<v.ang<<")";
        }
        else
            os<<"Vector object is invalid";
        return os;
    }

    //再为文件对象重载一个输出函数
    std::ofstream & operator<<(std::ofstream & ofs, const Vector & v)
    {
        if(v.mode == Vector::RECT)
            ofs<<"(x,y) = ("<<v.x<<","<<v.y<<")";
        else if(v.mode == Vector::POL)
        {
            ofs<<"(m,a) = ("<<v.mag<<","<<v.ang<<")";
        }
        else
            ofs<<"Vector object is invalid";
        return ofs;
    }
}   //end namespace VECTOR
//randwalk.cpp -- using Vector Class
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "vector.h"

int main()
{
    using namespace std;
    using VECTOR::Vector;
    srand(time(0));    //生成随机时间种子
    double direction;

    Vector step;    //表示移动的矢量
    Vector result(0.0,0.0);    //表示最终结果的矢量
    unsigned long steps = 0;
    double target;    //移动距离范围
    double dstep;    //每次移动的步长

    ofstream outfile;    //文件对象
    outfile.open("record.txt");    //打开文件
    cout<<"Enter target distance (q to quit): ";
    while(cin>>target)
    {
        cout<<"Enter step length: ";
        if(!(cin>>dstep))    //获取步长
            break;

        outfile<<"Target Distance: "<<target<<", Step Size: "<<dstep<<endl;
        while(result.magval() < target)
        {
            direction = rand()%360;    //随机生成一个方向(角度)
            step.reset(dstep,direction,Vector::POL);    //利用步长和方向设置移动的矢量
            result = result + step;    //(重载+)结果矢量更新
            outfile<<steps<<": (x,y) = "<<"("<<result.xval()<<","<<result.yval()<<")"<<endl;
            steps++;
        }

        outfile<<"After "<<steps<<" steps, the subject has the following location:\n";
        outfile<<result<<endl;
        result.polar_mode();
        outfile<<" or\n"<<result<<endl;
        outfile<<"Average outward distance per step = "<<result.magval()/steps<<endl;
        steps = 0;
        result.reset(0.0,0.0);
        cout<<"Enter target distance (q to quit): ";
    }
    outfile.close();    //关闭文件
    cout<<"Bye!\n";
    cin.clear();
    while(cin.get() != '\n')
        continue;

    return 0;
}

 

2.保留类的公有接口不变,修改私有部分,使得其不再存储长度mag和角度ang的值,而是在调用magval()和angval()时计算它们。重新测试,结果应与原来相同。

主函数没动。类的声明和实现如下:

//vector.h -- Vector Class
#ifndef _VECTOR_H_
#define _VECTOR_H_
#include<iostream>
#include<fstream>
namespace VECTOR
{
    class Vector
    {
    public:
        enum Mode{RECT,POL};

    private:
        double x;
        double y;
        Mode mode;
    //private methods for setting values
        void set_x(double m,double a);    //使用长度和方向换算x和y    
        void set_y(double m,double a);

    public:
        Vector();
        Vector(double n1, double n2, Mode form = RECT);
        void reset(double n1, double n2, Mode form = RECT);
        ~Vector();
        double xval() const { return x; }
        double yval() const { return y; }
        double magval() const;    //调用时通过x和y计算长度和方向
        double angval() const;
        void polar_mode();
        void rect_mode();
    //operator overloading
        Vector operator + (const Vector & b)const;
        Vector operator - (const Vector & b)const;
        Vector operator - ()const;
        Vector operator *(double n) const;
    //friends
        friend Vector operator*(double n, Vector & a);
        friend std::ostream & operator<<(std::ostream & os, const Vector & v);
        friend std::ofstream & operator<<(std::ofstream & ofs, const Vector & v);
    };
}    //end namespace VECTOR

#endif // VECTOR_H_INCLUDED
//vector.cpp -- Methods for Vector class
#include <cmath>
#include "vector.h"

using std::sqrt;
using std::sin;
using std::cos;
using std::atan;
using std::atan2;
using std::cout;

namespace VECTOR
{
    const double Rad_to_deg = 45.0 / atan(1.0);

    //private methods
    void Vector::set_x(double m,double a )
    {
        x = m * cos(a/Rad_to_deg);
    }

    void Vector::set_y(double m,double a )
    {
        y = m * sin(a/Rad_to_deg);
    }

    //public methods
    Vector::Vector()
    {
        x = y = 0.0;
        mode = RECT;
    }

    double Vector::magval() const
    {
        return sqrt(x*x +y*y);
    }

    double Vector::angval() const
    {
        if (x == 0.0 && y == 0.0)
        {
            return 0.0;
        }
        else
        {
            return atan2(y, x);
        }
    }

    //construct vector from rectangular or polar coordinate
    Vector::Vector(double n1, double n2, Mode form)
    {
        mode = form;
        if (form == RECT)
        {
            x = n1;
            y = n2;
        }
        else if (form == POL)
        {
            set_x(n1,n2);
            set_y(n1,n2);
        }
        else
        {
            cout << "Incorrect 3rd argument to Vector() -- ";
            cout << "Vector set to 0\n";
            x = y = 0;
            mode = RECT;
        }
    }

    void Vector::reset(double n1, double n2, Mode form)
    {
        mode = form;
        if (form == RECT)
        {
            x = n1;
            y = n2;
        }
        else if (form == POL)
        {
            set_x(n1,n2);
            set_y(n1,n2);
        }
        else
        {
            cout << "Incorrect 3rd argument to Vector() -- ";
            cout << "Vector set to 0\n";
            x = y = 0;
            mode = RECT;
        }
    }

    Vector::~Vector()
    {
    }

    void Vector::rect_mode()
    {
        mode = RECT;
    }

    void Vector::polar_mode()
    {
        mode = POL;
    }

    Vector Vector::operator + (const Vector & b)const
    {
        return Vector(x + b.x,y + b.y);
    }

    Vector Vector::operator - (const Vector & b )const
    {
        return Vector(x - b.x,y - b.y);
    }

    Vector Vector::operator - ()const
    {
        return Vector(-x,-y);
    }

    Vector Vector::operator * (double n)const
    {
        return Vector(n*x,n*y);
    }

    Vector operator * (double n,const Vector & a)
    {
        return a * n;
    }

    //display coordinates
    std::ostream & operator <<(std::ostream & os, const Vector &v)
    {
        if(v.mode == Vector::RECT)
            os<<"(x,y) = ("<<v.x<<","<<v.y<<")";
        else if(v.mode == Vector::POL)
        {
            os<<"(m,a) = ("<<v.magval()<<","<<v.angval()<<")";
        }
        else
            os<<"Vector object is invalid";
        return os;
    }

    //再为文件对象重载一个输出函数
    std::ofstream & operator<<(std::ofstream & ofs, const Vector & v)
    {
        if(v.mode == Vector::RECT)
            ofs<<"(x,y) = ("<<v.x<<","<<v.y<<")";
        else if(v.mode == Vector::POL)
        {
            ofs<<"(m,a) = ("<<v.magval()<<","<<v.angval()<<")";
        }
        else
            ofs<<"Vector object is invalid";
        return ofs;
    }
}   //end namespace VECTOR

 

3.继续修改上面的程序,不再写入每次测试的具体结果,而是由用户指定特定的测试次数N,写入N次测试的最大步数和最小步数。

//randwalk.cpp -- using Vector Class
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "vector.h"

int main()
{
    using namespace std;
    using VECTOR::Vector;
    srand(time(0));    //生成随机时间种子
    double direction;

    Vector step;    //表示移动的矢量
    Vector result(0.0,0.0);    //表示最终结果的矢量
    unsigned long steps = 0;
    unsigned long max_steps;
    unsigned long min_steps;
    double target = 0;    //移动距离范围
    double dstep = 0;    //每次移动的步长
    unsigned test_times = 0;
    unsigned N;    //用户指定的测试次数

    //测试准备
    ofstream outfile;    //文件对象
    outfile.open("record.txt");    //打开文件
    cout<<"Enter times you want to test: ";
    if(cin>>N)
    {
            cout<<"Enter target distance: ";
            cin>>target;
            cout<<"Enter step length: ";
            cin>>dstep;
    }
    else
    {
        N = 1;
    }
    outfile<<"Target Distance: "<<target<<", Step Size: "<<dstep<<endl;
    unsigned long * all_steps = new unsigned long [N];    //分配用于存储所有测试步数的数组指针

    //测试过程
    while(test_times<N)
    {
        while(result.magval() < target)
        {
            direction = rand()%360;    //随机生成一个方向(角度)
            step.reset(dstep,direction,Vector::POL);    //利用步长和方向设置移动的矢量
            result = result + step;    //(重载+)结果矢量更新
            steps++;
        }
        all_steps[test_times] = steps;    //存储此次测试的步数
        outfile<<"Test "<<test_times<<" used "<<steps<<" steps."<<endl;

        steps = 0;
        result.reset(0.0,0.0);
        test_times++;
    }

    //测试结果
    outfile<<"You have tested "<<N<<" times."<<endl;
    max_steps = min_steps = all_steps[0];    //比较最大和最小步数
    for(unsigned i=0;i<N;i++)
    {
        if(all_steps[i]>max_steps)
            max_steps = all_steps[i];
        else{};

        if(all_steps[i]<min_steps)
            min_steps = all_steps[i];
        else{};
    }
    outfile<<"Max steps: "<<max_steps<<endl;
    outfile<<"Minimum steps: "<<min_steps<<endl;

    outfile.close();    //关闭文件
    cout<<"Bye!\n";
    delete[]all_steps;    //删除动态内存
    cin.clear();
    while(cin.get() != '\n')
        continue;

    return 0;
}

输出结果的形式:

 

7.实现一个复数类,使之能进行基本的加减乘运算,其中需要重载“<<”、“>>”、“~”、“+”、“-”、“*”等运算符,并定义友元函数。

//complex0.h -- Declaration of Complex Class
#ifndef _COMPLEX0_H_
#define _COMPLEX0_H_
#include<iostream>
using namespace std;

class Ccomplex
{
private:
    double m_real ;
    double m_imag ;

public:
    Ccomplex();
    ~Ccomplex();
    void set_real(double i);
    void set_imag(double r);
    Ccomplex(double r ,double i );
    Ccomplex operator +(const Ccomplex & c) const;
    Ccomplex operator -(const Ccomplex & c) const;
    Ccomplex operator *(const Ccomplex & c) const;
    friend istream & operator >> (istream & is, Ccomplex & c);
    friend ostream & operator << (ostream & os, const Ccomplex  c);
    friend Ccomplex operator ~(const Ccomplex c);    //如果按引用传递上一句重载函数会不匹配,所以按值传递
    friend Ccomplex operator *(const double n,const Ccomplex c);

};

#endif // _COMPLEX0_H_
//complex0.cpp -- Methods of Complex Class
#include"complex0.h"

Ccomplex::Ccomplex()
{
    m_real = 0;
    m_imag = 0;
}

Ccomplex::~Ccomplex()
{

}

Ccomplex::Ccomplex(double r = 0,double i = 0)
{
    m_real = r;
    m_imag = i;
}

void Ccomplex::set_imag(double i)
{
    m_imag = i;
}

void Ccomplex::set_real(double r)
{
    m_real = r;
}

Ccomplex operator ~(const Ccomplex c)
{
   return Ccomplex(c.m_real,-c.m_imag);
}

Ccomplex Ccomplex::operator +(const Ccomplex & c) const
{
     return Ccomplex(m_real + c.m_real,m_imag + c.m_imag);
}

Ccomplex Ccomplex::operator -(const Ccomplex & c) const
{
     return Ccomplex(m_real - c.m_real,m_imag - c.m_imag);
}

Ccomplex Ccomplex::operator *(const Ccomplex & c) const
{
     return Ccomplex(m_real*c.m_real - m_imag*c.m_imag , m_real*c.m_imag + m_imag*c.m_real);
}

Ccomplex operator *(const double n,const Ccomplex c)
{
    return Ccomplex(n*c.m_real,n*c.m_imag);
}

istream & operator >> (istream & is, Ccomplex & c)
 {
     double tr,ti;
     cout<<"real: ";
     is >> tr;
     cout<<"imaginary: ";
     is >> ti;
     c.set_real(tr);
     c.set_imag(ti);
     return is;
 }

ostream & operator << (ostream & os, const Ccomplex c)
 {
     if(c.m_imag > 0)
     {
         os<<"("<<c.m_real<<"+"<<c.m_imag<<"i)";
     }
     else if(c.m_imag == 0)
     {
         os<<c.m_real<<endl;
     }
     else
     {
         os<<"("<<c.m_real<<c.m_imag<<"i)";
     }
     return os;
 }
//main.cpp -- Using Complex Class
#include <iostream>
#include"complex0.h"

int main()
{
    Ccomplex a(3.0,4.0);
    Ccomplex c;

    cout<<"Enter a complex number (q to quit):\n";
    while(cin>>c)
    {
        cout<<"c is "<<c<<'\n';
        cout<<"complex conjugate is "<<~c<<'\n';
        cout<<"a is "<<a<<'\n';
        cout<<"a + c is "<<a + c<<'\n';
        cout<<"a - c is "<<a - c<<'\n';
        cout<<"a * c is "<<a * c<<'\n';
        cout<<"2 * c is "<<2 * c<<'\n';
        cout<<"Enter a complex number (q to quit):\n";
    }
    cout<<"Done!\n";

    return 0;
}

 

调试的过程中遇到了很多问题,总结一下:

1.友元函数和类本体有着同样的权力,能够访问私有成员

2.给出友元函数的定义时,不用加上类的“::”的解析符,和正常的函数定义一样

3.如果不是在类成员函数的实现里面的话,类本身是调不出它的私有成员的。比如在主函数里想通过 “.” 调出私有成员赋给另一个变量是不行的,除非通过公共接口。

4.分清楚重载运算符是想用于什么样形式的运算。如果想定义一种【该类——该运算符——其它类型】的运算,使用成员函数重载,“其它类型”以参数传递(如上面例程中的加减号重载);如果想定义一种【其它类型——该运算符——该类】的运算,使用友元函数重载(如上面例程中的>>,<<,~的重载)。

 

posted @ 2019-08-30 16:25  MorpheusDong  阅读(343)  评论(0编辑  收藏  举报