• 《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
    ";
                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
    ";
                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:
    ";
            outfile<<result<<endl;
            result.polar_mode();
            outfile<<" or
    "<<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!
    ";
        cin.clear();
        while(cin.get() != '
    ')
            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
    ";
                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
    ";
                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!
    ";
        delete[]all_steps;    //删除动态内存
        cin.clear();
        while(cin.get() != '
    ')
            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):
    ";
        while(cin>>c)
        {
            cout<<"c is "<<c<<'
    ';
            cout<<"complex conjugate is "<<~c<<'
    ';
            cout<<"a is "<<a<<'
    ';
            cout<<"a + c is "<<a + c<<'
    ';
            cout<<"a - c is "<<a - c<<'
    ';
            cout<<"a * c is "<<a * c<<'
    ';
            cout<<"2 * c is "<<2 * c<<'
    ';
            cout<<"Enter a complex number (q to quit):
    ";
        }
        cout<<"Done!
    ";
    
        return 0;
    }

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

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

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

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

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

  • 相关阅读:
    君の知らない物語
    2.OSI各层概述
    [ unittest ] 使用初体验
    1.分层结构、协议、接口、服务
    [flask] jinja自定义filter来过滤html标签
    [Flask] Flask问题集(后端模板渲染项目)
    [服务器部署] Flask + virtualenv + uWSGI + Nginx 遇到的问题
    android控件的对齐方式(转)
    AIDL
    歌词的获取
  • 原文地址:https://www.cnblogs.com/banmei-brandy/p/11425228.html
Copyright © 2020-2023  润新知